package handler import ( "bytes" "context" "encoding/json" "fmt" "io/ioutil" "net/http" "github.com/micro/micro/v3/service/config" "github.com/micro/micro/v3/service/errors" log "github.com/micro/micro/v3/service/logger" pb "github.com/micro/services/email/proto" ) type sendgridConf struct { Key string `json:"key"` EmailFrom string `json:"email_from"` } func NewEmailHandler() *Email { c := sendgridConf{} val, err := config.Get("sendgridapi") if err != nil { log.Warnf("Error getting config: %v", err) } err = val.Scan(&c) if err != nil { log.Warnf("Error scanning config: %v", err) } if len(c.Key) == 0 { log.Fatalf("Sendgrid API key not configured") } return &Email{ c, } } type Email struct { config sendgridConf } func (e *Email) Send(ctx context.Context, request *pb.SendRequest, response *pb.SendResponse) error { if len(request.From) == 0 { return errors.BadRequest("email.send.validation", "Missing from address") } if len(request.To) == 0 { return errors.BadRequest("email.send.validation", "Missing to address") } if len(request.Subject) == 0 { return errors.BadRequest("email.send.validation", "Missing subject") } if len(request.TextBody) == 0 && len(request.HtmlBody) == 0 { return errors.BadRequest("email.send.validation", "Missing email body") } if err := e.sendEmail(request); err != nil { log.Errorf("Error sending email: %v\n", err) return errors.InternalServerError("email.sendemail", "Error sending email") } return nil } // sendEmail sends an email invite via the sendgrid API using the // pre-designed email template. Docs: https://bit.ly/2VYPQD1 func (e *Email) sendEmail(req *pb.SendRequest) error { content := []interface{}{} if len(req.TextBody) > 0 { content = append(content, map[string]string{ "type": "text/plain", "value": req.TextBody, }) } if len(req.HtmlBody) > 0 { content = append(content, map[string]string{ "type": "text/html", "value": req.HtmlBody, }) } reqBody, _ := json.Marshal(map[string]interface{}{ "from": map[string]string{ "email": e.config.EmailFrom, "name": req.From, }, "reply_to": map[string]string{ "email": e.config.EmailFrom, "name": req.From, }, "subject": req.Subject, "content": content, "personalizations": []interface{}{ map[string]interface{}{ "to": []map[string]string{ { "email": req.To, }, }, }, }, }) httpReq, err := http.NewRequest("POST", "https://api.sendgrid.com/v3/mail/send", bytes.NewBuffer(reqBody)) if err != nil { return err } httpReq.Header.Set("Authorization", "Bearer "+e.config.Key) httpReq.Header.Set("Content-Type", "application/json") rsp, err := new(http.Client).Do(httpReq) if err != nil { return fmt.Errorf("could not send email, error: %v", err) } defer rsp.Body.Close() if rsp.StatusCode < 200 || rsp.StatusCode > 299 { bytes, err := ioutil.ReadAll(rsp.Body) if err != nil { return err } return fmt.Errorf("could not send email, error: %v", string(bytes)) } return nil }