Reputation: 909
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": "[email protected]"
}
],
"subject": "Sending with SendGrid is Fun"
}
],
"from": {
"email": "[email protected]"
},
"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)
}
Upvotes: 1
Views: 912
Reputation: 10613
SendGrid document the minimum needed code to send an email with Go on AppEngine in
How to send email using Go. It differs from @birju-prajapati's answer; the client is created with sendgrid.NewSendClient
.
An API key must be generated and your development environment updated with your SENDGRID_API_KEY
. Then install sendgrid-go and its dependencies with go get github.com/sendgrid/sendgrid-go
.
// using SendGrid's Go Library
// https://github.com/sendgrid/sendgrid-go
package main
import (
"fmt"
"log"
"os"
"github.com/sendgrid/sendgrid-go"
"github.com/sendgrid/sendgrid-go/helpers/mail"
)
func main() {
from := mail.NewEmail("Example User", "[email protected]")
subject := "Sending with SendGrid is Fun"
to := mail.NewEmail("Example User", "[email protected]")
plainTextContent := "and easy to do anywhere, even with Go"
htmlContent := "<strong>and easy to do anywhere, even with Go</strong>"
message := mail.NewSingleEmail(from, subject, to, plainTextContent, htmlContent)
client := sendgrid.NewSendClient(os.Getenv("SENDGRID_API_KEY"))
response, err := client.Send(message)
if err != nil {
log.Println(err)
} else {
fmt.Println(response.StatusCode)
fmt.Println(response.Body)
fmt.Println(response.Headers)
}
}
Upvotes: 0
Reputation: 11
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)}
Upvotes: 1
Reputation: 909
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": "[email protected]"}]}],"from": {"email": "[email protected]"},"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!
Upvotes: 2
Reputation: 3923
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
Upvotes: 1