问题
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
- 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