How do I send email through the Gmail Go SDK?
I am trying to send a new email via the gmail package . However, the Message type that send requires is poorly documented. Most of the fields appear to be used for parsing or reading emails. The only field that makes sense (to some extent) for the dispatch method is the payload of type MessagePart , although I can't figure out how to generate the MessagePartBody as it seems to be a kind of mime type. Below is the code I have.
func (em *Email) SendMessage(cl *Client) error {
config.ClientId = cl.Username
config.ClientSecret = cl.Password
t := &oauth.Transport{
Config: config,
Transport: http.DefaultTransport,
}
var tk oauth.Token
err := json.Unmarshal([]byte(cl.Meta), &tk)
t.Token = &tk
if err != nil {
log.Errorf("meta %v, err %v", cl.Meta, err)
return err
}
gmailService, err := gmail.New(t.Client())
if err != nil {
log.Error(err)
return err
}
p := gmail.MessagePart{}
p.Headers = append(p.Headers, &gmail.MessagePartHeader{
Name: "From",
Value: em.FromEmail,
})
p.Headers = append(p.Headers, &gmail.MessagePartHeader{
Name: "To",
Value: em.ToEmail,
})
p.Headers = append(p.Headers, &gmail.MessagePartHeader{
Name: "Subject",
Value: em.Subject,
})
emsg := base64.StdEncoding.EncodeToString(em.Message)
log.Info(emsg)
msg := gmail.Message{
Payload: &p,
Raw: "",
}
_, err = gmailService.Users.Messages.Send("me", &msg).Do()
if err != nil {
log.Error(err)
return err
}
return err
}
The "REST" API is even more confusing. This requires a parameter uploadType
(WTF to load) and a field raw
, which I assume is a raw message, which requires the format provided by messages.get. Why are you sending a message from your inbox that will literally "resend" as indicated on the list of receipts? Am I the only one who thinks this API (or at least the documentation) is just crap?
source to share
It was a little tricky, but this is how you can send emails via the GMAIL API
import(
"code.google.com/p/goauth2/oauth"
"code.google.com/p/google-api-go-client/gmail/v1"
log "github.com/golang/glog"
"encoding/base64"
"encoding/json"
"net/mail"
"strings"
)
type Email struct {
FromName, FromEmail, ToName, ToEmail, Subject string
Message string
}
func (em *Email) SendMessage(cl *Client) error {
config.ClientId = cl.Username //oauth clientID
config.ClientSecret = cl.Password //oauth client secret
t := &oauth.Transport{
Config: config,
Transport: http.DefaultTransport,
}
var tk oauth.Token
err := json.Unmarshal([]byte(cl.Meta), &tk)
t.Token = &tk
if err != nil {
log.Errorf("meta %v, err %v", cl.Meta, err)
return err
}
gmailService, err := gmail.New(t.Client())
if err != nil {
log.Error(err)
return err
}
from := mail.Address{em.FromName, em.FromEmail}
to := mail.Address{em.ToName, em.ToEmail}
header := make(map[string]string)
header["From"] = from.String()
header["To"] = to.String()
header["Subject"] = encodeRFC2047(em.Subject)
header["MIME-Version"] = "1.0"
header["Content-Type"] = "text/html; charset=\"utf-8\""
header["Content-Transfer-Encoding"] = "base64"
var msg string
for k, v := range header {
msg += fmt.Sprintf("%s: %s\r\n", k, v)
}
msg += "\r\n" + em.Message
gmsg := gmail.Message{
Raw: encodeWeb64String([]byte(msg)),
}
_, err = gmailService.Users.Messages.Send("me", &gmsg).Do()
if err != nil {
log.Errorf("em %v, err %v", gmsg, err)
return err
}
return err
}
func encodeRFC2047(s string) string {
// use mail rfc2047 to encode any string
addr := mail.Address{s, ""}
return strings.Trim(addr.String(), " <>")
}
func encodeWeb64String(b []byte) string {
s := base64.URLEncoding.EncodeToString(b)
var i = len(s) - 1
for s[i] == '=' {
i--
}
return s[0 : i+1]
}
source to share
Similar to @hey's answer, but I removed it and allowed the email to insert new lines in the email body through \n
and display correctly in the email client. Also, @hey doesn't use the new supported Gmail API . Here's the final code:
import (
"encoding/base64"
"golang.org/x/net/context"
"golang.org/x/oauth2"
"golang.org/x/oauth2/google"
"google.golang.org/api/gmail/v1"
"encoding/json"
"net/mail"
)
type Email struct {
FromName string
FromEmail string
ToName string
ToEmail string
Subject string
Message string
}
func (em *Email) sendMailFromEmail() error {
b, err := ioutil.ReadFile("credentials.json")
if err != nil {
log.Fatalf("Unable to read client secret file: %v", err)
}
// If modifying these scopes, delete your previously saved token.json.
config, err := google.ConfigFromJSON(b, gmail.GmailSendScope)
if err != nil {
log.Fatalf("Unable to parse client secret file to config: %v", err)
}
cl := getClientMail(config)
gmailService, err := gmail.New(cl)
if err != nil {
log.Fatalf("Unable to retrieve Gmail client: %v", err)
}
from := mail.Address{em.FromName, em.FromEmail}
to := mail.Address{em.ToName, em.ToEmail}
header := make(map[string]string)
header["From"] = from.String()
header["To"] = to.String()
header["Subject"] = em.Subject
header["MIME-Version"] = "1.0"
header["Content-Type"] = "text/plain; charset=\"utf-8\""
header["Content-Transfer-Encoding"] = "base64"
var msg string
for k, v := range header {
msg += fmt.Sprintf("%s: %s\r\n", k, v)
}
msg += "\r\n" + em.Message
gmsg := gmail.Message{
Raw: base64.RawURLEncoding.EncodeToString([]byte(msg)),
}
_, err = gmailService.Users.Messages.Send("me", &gmsg).Do()
if err != nil {
log.Printf("em %v, err %v", gmsg, err)
return err
}
return err
}
I have not included the following features: getClient, getTokenFromWeb, tokenFromFile and saveToken. You can find them and learn how to enable the Gmail API using this tutorial from Google.
source to share