如何通过Gmail Go SDK发送电子邮件?

时间:2014-08-19 11:57:49

标签: go gmail gmail-api

我正在尝试通过gmail包发送新电子邮件。但是,Message方法所需的send类型记录很少。大多数字段似乎用于实际解析/阅读电子邮件。对于send方法唯一有意义的字段(在某种程度上)是MessagePart类型的Payload,虽然我无法弄清楚如何生成MessagePartBody,因为它似乎是一种mime类型。下面是我到目前为止的代码。

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
}

“REST”API更令人困惑。它需要一个uploadType参数(上传WTF)和一个raw字段,我猜这是一个原始消息,它需要一个由messages.get提供的格式。为什么你会从收件箱中发送一条消息,这个消息就像你在收据清单上一样“重新发送”?我是唯一一个认为这个API(或者至少是文档)只是垃圾的人吗?

2 个答案:

答案 0 :(得分:4)

这有点棘手,但以下是您可以通过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's 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]
}

答案 1 :(得分:0)

类似于@hey的答案,但我整理了一下,并允许电子邮件通过\n在电子邮件正文中添加换行符,并正确显示在电子邮件客户端上。另外,@ hey没有使用新的受支持的Gmail API。这是最终代码:

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
}

我没有包括以下功能:getClient,getTokenFromWeb,tokenFromFile和saveToken。您可以找到它们,并通过Google的tutorial了解如何启用Gmail API。