带有 Go 和 gmail.NewService 的 Gmail API 无效内存地址或 nil

我对 gmail api 的新 NewService 功能有疑问。如果我使用已弃用的 gmail.New() 一切正常。使用 NewService() 我得到invalid memory address or nil pointer dereference


我的实现如下


type MailData struct {

    To      string

    Name    string

    Subject string

    Content template.HTML

}    


func doSend(msg *gmail.Message, srv *gmail.Service) error {

    _, err := srv.Users.Messages.Send("me", msg).Do()

    if err != nil {

        return err

    }

    return nil

}


func ComposeMessage(m models.MailData) *gmail.Message {


    var gmailMessage gmail.Message


    from := mail.Address{Name: "Sender", Address: os.Getenv("MAIL_FROM")}

    replyTo := os.Getenv("MAIL_REPLYTO")

    to := mail.Address{Name: m.Name, Address: m.To}


    header := make(map[string]string)

    header["From"] = from.String()

    header["Reply-To"] = replyTo

    header["To"] = to.String()

    header["Subject"] = m.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" + string(m.Content)


    gmailMessage.Raw = base64.RawURLEncoding.EncodeToString([]byte(msg))

    return &gmailMessage

}

使用旧的 gmail.New() 有效,但它指出该功能已弃用,因此我需要将其更改为新的 gmail.NewService。虽然像下面这样实现它是行不通的


func sendGMail(m models.MailData) error {

    credentials := "../gmail_credentials.json"


    ctx := context.Background()

    srv, err := gmail.NewService(

        ctx,

        option.WithCredentialsFile(credentials),

        option.WithScopes("https://www.googleapis.com/auth/gmail.send"),

    )

    if err != nil {

        return errors.New(fmt.Sprintf("unable to retrieve gmail client: %s", err))

    }


    // Create message

    gMessage := ComposeMessage(m)


    if err := doSend(gMessage, srv); err != nil {

        return errors.New(fmt.Sprintf("could not send mail: %s", err))

    }

    fmt.Println("Email sent")


    return nil

}


BIG阳
浏览 66回答 1
1回答

守着星空守着你

这个问题并不那么明显,但很容易解决。在初始化时,gmail.NewService()我需要将配置参数作为选项传递,就像之前的实现gmail.New()是使用所以之前是client := getClient(config)srv, err := gmail.New(client)现在是client := getClient(config)ctx := context.Background()srv, err := gmail.NewService(    ctx,    option.WithHTTPClient(client),)在 Go 的 Gmail API 实现的更多上下文中,您需要使用所有使用的函数https://developers.google.com/gmail/api/quickstart/go或https://github.com/googleworkspace/go-samples/blob/master/gmail/quickstart/quickstart.go并将它们放入您的 go 文件中。这些将生成 AccessToken 和凭据,如果您正确遵循指南,则需要将其保存为 json 文件并重复使用。credentials.json 用于更新您的 AccessToken。现在代替使用gmail.New(),正确的方法是使用如上所示的函数。整个sendGmail函数如下func sendGMail(m models.MailData) error {    credentials := "../gmail_credentials.json"    b, err := ioutil.ReadFile(credentials)    if err != nil {        return errors.New(fmt.Sprint("unable to read credentials file:", err))    }    config, err := google.ConfigFromJSON(b, gmail.GmailSendScope)    if err != nil {        return errors.New(fmt.Sprint("unable to parse credentials file config:", err))    }    client := getClient(config)    ctx := context.Background()    srv, err := gmail.NewService(        ctx,        option.WithHTTPClient(client),        option.WithScopes("https://www.googleapis.com/auth/gmail.send"),    )    if err != nil {        return fmt.Errorf("unable to retrieve gmail client: %s", err)    }    // Create message    gMessage := ComposeMessage(m)    if err := doSend(gMessage, srv); err != nil {        return fmt.Errorf("could not send mail: %s", err)    }    fmt.Println("Email sent")    return nil}
打开App,查看更多内容
随时随地看视频慕课网APP