How to use SendGrid from Google App Engine Golang?

柔情痞子 提交于 2019-12-11 13:04:13

问题


The example code at: https://sendgrid.com/blog/send-email-go-google-app-engine/

My guess this is very old sample code to use sendgrid-go on Google App Engine.

I've attempted 4 permutations and failed each time with:

https://api.sendgrid.com/v3/mail/send: http.DefaultTransport and http.DefaultClient are not available in App Engine. See https://cloud.google.com/appengine/docs/go/urlfetch/

Here is a minimum hardcoded attempt with some logging:

package sendgridgo


import(
    "github.com/sendgrid/sendgrid-go"
    "fmt"
    _"google.golang.org/appengine"
    "net/http"
    "google.golang.org/appengine/log"
    "google.golang.org/appengine"
    "google.golang.org/appengine/urlfetch"
     _ "github.com/sendgrid/sendgrid-go/helpers/mail"
)

func init(){
    http.HandleFunc("/", IndexHandler)
    appengine.Main()
}

func IndexHandler (w http.ResponseWriter, r *http.Request){
    ctx := appengine.NewContext(r)

    log.Infof(ctx, "IndexHandler")
    sg := sendgrid.NewSendClient("SENDGRID_API_KEY")
    log.Infof(ctx, "%v", sg)
    bob := urlfetch.Client(ctx)

    log.Infof(ctx, "UrlFetchClient %v", bob)
    //resp, err := sg.Send(m)
    request := sendgrid.GetRequest("SENDGRID_API_KEY", "/v3/mail/send", "https://api.sendgrid.com")
    request.Method = "POST"

    request.Body = []byte(` {
    "personalizations": [
        {
            "to": [
                {
                    "email": "darian.hickman@gmail.com"
                }
            ],
            "subject": "Sending with SendGrid is Fun"
        }
    ],
    "from": {
        "email": "darian.hickman@villagethegame.com"
    },
    "content": [
        {
            "type": "text/plain",
            "value": "and easy to do anywhere, even with Go"
        }
    ]
}`)
    resp, err := sendgrid.API(request)

    if err != nil{
        log.Errorf(ctx, "Failed %v", err)
    }

    fmt.Fprint(w, resp)


}

回答1:


After 8 different attempts, including trying an example published in Google Cloud docs for using Sendgrid, an example from Sendgrid blog, and trying to use deprecated versions of Sendgrid api, I found Sendgrid curl examples at:

https://sendgrid.com/docs/Classroom/Send/v3_Mail_Send/curl_examples.html

curl --request POST \
  --url https://api.sendgrid.com/v3/mail/send \
  --header 'Authorization: Bearer YOUR_API_KEY' \
  --header 'Content-Type: application/json' \
  --data '{"personalizations": [{"to": [{"email": "recipient@example.com"}]}],"from": {"email": "sendeexampexample@example.com"},"subject": "Hello, World!","content": [{"type": "text/plain", "value": "Heya!"}]}'

I then translated the HelloWorld example to into URLFetch usage

client := urlfetch.Client(ctx)

request, err := http.NewRequest("POST", "https://api.sendgrid.com/v3/mail/send", buf)
    if err != nil {
        log.Errorf(ctx, "Failed Request %v", request)
    }
    request.Header.Set("Authorization", "Bearer SENDGRID_API_KEY")
    request.Header.Set("Content-Type", "application/json")
    resp, err := client.Do(request)

One Easter weekend, later, it works!




回答2:


You were on the right track, but skipped overriding the default sendgrid client with urlfetch client.

.
.
.
func IndexHandler (w http.ResponseWriter, r *http.Request){
    ctx := appengine.NewContext(r)    
    sg := sendgrid.NewSendClient("REPLACE_WITH_API_KEY")
    bob := urlfetch.Client(ctx)

    sg.Client = bob

    request := sendgrid.GetRequest("REPLACE_WITH_API_KEY", "/v3/mail/send", "https://api.sendgrid.com")
    request.Method = "POST"
.
.
.

Explanation

The error occurs as sendgrid tries to fetch a url with the default net/http method.

Quoting AppEngine Documentation

App Engine uses the URL Fetch service to issue outbound HTTP(S) requests. To issue an outbound HTTP request, use the http package as usual, but create your client using urlfetch.Client. urlfetch.Client returns an *http.Client that uses urlfetch.Transport, which is an implementation of the http.RoundTripper interface that makes requests using the URL Fetch API.

The workaround is to override the Sendgrid client to use urlfetch

        context := appengine.NewContext(r)
        sg := sendgrid.NewSendClient(os.Getenv("SENDGRID_API_KEY"))
        sg.Client = urlfetch.Client(context)

References

  1. GCloud Documentation- Issuing HTTP(S) Requests in App Engine Golang



回答3:


The solution is documented in sendgrid.go:

// DefaultClient is used if no custom HTTP client is defined
var DefaultClient = rest.DefaultClient

So just do this at the beginning of your send, where ctx is appengine.NewContext(req):

sendgrid.DefaultClient = &rest.Client{HTTPClient: urlfetch.Client(ctx)}


来源:https://stackoverflow.com/questions/49596003/how-to-use-sendgrid-from-google-app-engine-golang

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!