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

huangapple go评论92阅读模式
英文:

How to send email through Gmail Go SDK?

问题

我正在尝试通过gmail包发送一封新邮件。然而,send方法所需的Message类型文档不够详细。大多数字段似乎用于解析/读取邮件。对于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参数(上传什么?)和一个raw字段,我猜这是原始消息,需要通过messages.get提供的格式。为什么要从收件箱发送一条消息,而这条消息实际上是一个“转发”?难道只有我觉得这个API(或者至少是文档)很糟糕吗?

英文:

I'm trying to send a new email through the gmail package . However the Message type which is required by the send method is poorly documented. Most of the fields seem used to actually parse/read emails. The only field which makes sense (at some degree) for the send method is Payload of type MessagePart though I can't figure it out how to generate the MessagePartBody as it seems to be a kind of mime type. Below is the code I have so far.

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. It requires an uploadType param (WTF to upload) and a raw field which I guess is the raw message which requires a format provided by messages.get. Why would you send a message from your inbox which literally would be a 'resend' as your are on the receipt list ? Am I the only one who thinks this API(or at least the documentation) is just crap ?

答案1

得分: 6

这是通过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]
}

希望对你有帮助!

英文:

It was a bit tricky but here is how you can send emails through the GMAIL API

import(
&quot;code.google.com/p/goauth2/oauth&quot;
&quot;code.google.com/p/google-api-go-client/gmail/v1&quot;
log &quot;github.com/golang/glog&quot;
&quot;encoding/base64&quot;
&quot;encoding/json&quot;
&quot;net/mail&quot;
&quot;strings&quot;
)
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 := &amp;oauth.Transport{
Config:    config,
Transport: http.DefaultTransport,
}
var tk oauth.Token
err := json.Unmarshal([]byte(cl.Meta), &amp;tk)
t.Token = &amp;tk
if err != nil {
log.Errorf(&quot;meta %v, err %v&quot;, 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[&quot;From&quot;] = from.String()
header[&quot;To&quot;] = to.String()
header[&quot;Subject&quot;] = encodeRFC2047(em.Subject)
header[&quot;MIME-Version&quot;] = &quot;1.0&quot;
header[&quot;Content-Type&quot;] = &quot;text/html; charset=\&quot;utf-8\&quot;&quot;
header[&quot;Content-Transfer-Encoding&quot;] = &quot;base64&quot;
var msg string
for k, v := range header {
msg += fmt.Sprintf(&quot;%s: %s\r\n&quot;, k, v)
}
msg += &quot;\r\n&quot; + em.Message
gmsg := gmail.Message{
Raw: encodeWeb64String([]byte(msg)),
}
_, err = gmailService.Users.Messages.Send(&quot;me&quot;, &amp;gmsg).Do()
if err != nil {
log.Errorf(&quot;em %v, err %v&quot;, gmsg, err)
return err
}
return err
}
func encodeRFC2047(s string) string {
// use mail&#39;s rfc2047 to encode any string
addr := mail.Address{s, &quot;&quot;}
return strings.Trim(addr.String(), &quot; &lt;&gt;&quot;)
}
func encodeWeb64String(b []byte) string {
s := base64.URLEncoding.EncodeToString(b)
var i = len(s) - 1
for s[i] == &#39;=&#39; {
i--
}
return s[0 : i+1]
}

答案2

得分: 1

与@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教程中找到它们,并学习如何通过Gmail API进行设置。

英文:

Similar to @hey 's answer, but I tidied it up, and allowed the email to put newlines in the email body through \n and show up correctly on the email client. Also, @hey is not using the new supported Gmail API. Here is the final code:

import (
&quot;encoding/base64&quot;
&quot;golang.org/x/net/context&quot;
&quot;golang.org/x/oauth2&quot;
&quot;golang.org/x/oauth2/google&quot;
&quot;google.golang.org/api/gmail/v1&quot;
&quot;encoding/json&quot;
&quot;net/mail&quot;
)
type Email struct {
FromName  string
FromEmail string
ToName    string
ToEmail   string
Subject   string
Message   string
}
func (em *Email) sendMailFromEmail() error {
b, err := ioutil.ReadFile(&quot;credentials.json&quot;)
if err != nil {
log.Fatalf(&quot;Unable to read client secret file: %v&quot;, err)
}
// If modifying these scopes, delete your previously saved token.json.
config, err := google.ConfigFromJSON(b, gmail.GmailSendScope)
if err != nil {
log.Fatalf(&quot;Unable to parse client secret file to config: %v&quot;, err)
}
cl := getClientMail(config)
gmailService, err := gmail.New(cl)
if err != nil {
log.Fatalf(&quot;Unable to retrieve Gmail client: %v&quot;, err)
}
from := mail.Address{em.FromName, em.FromEmail}
to := mail.Address{em.ToName, em.ToEmail}
header := make(map[string]string)
header[&quot;From&quot;] = from.String()
header[&quot;To&quot;] = to.String()
header[&quot;Subject&quot;] = em.Subject
header[&quot;MIME-Version&quot;] = &quot;1.0&quot;
header[&quot;Content-Type&quot;] = &quot;text/plain; charset=\&quot;utf-8\&quot;&quot;
header[&quot;Content-Transfer-Encoding&quot;] = &quot;base64&quot;
var msg string
for k, v := range header {
msg += fmt.Sprintf(&quot;%s: %s\r\n&quot;, k, v)
}
msg += &quot;\r\n&quot; + em.Message
gmsg := gmail.Message{
Raw: base64.RawURLEncoding.EncodeToString([]byte(msg)),
}
_, err = gmailService.Users.Messages.Send(&quot;me&quot;, &amp;gmsg).Do()
if err != nil {
log.Printf(&quot;em %v, err %v&quot;, gmsg, err)
return err
}
return err
}

I did not include the following functions: getClient, getTokenFromWeb, tokenFromFile, and saveToken. You can find them, and learn how to enable the Gmail API through this tutorial by Google.

huangapple
  • 本文由 发表于 2014年8月19日 19:57:48
  • 转载请务必保留本文链接:https://go.coder-hub.com/25382821.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定