Send an email
One message now or later, with attachments, or a hundred in one request.
Send a message
sent, err := client.Emails.Send(ctx, nextmail.Body{ "from": "Acme Billing <billing@acme.com>", "to": []string{"ada@example.com", "grace@example.com"}, "replyTo": "support@acme.com", "subject": "Your September invoice", "html": "<p>The invoice is attached.</p>", "text": "The invoice is attached.", "tags": nextmail.Body{"invoice": "inv_2026_09_4192"},})if err != nil { return err} fmt.Println(sent.ID(), sent.String("status"))to, cc and bcc take one address or a list, and an address is text such as Ada <ada@example.com> or a map with email and name. The body comes from html and text, from a stored template, or from a draftId.
Every send carries an idempotency key. The client makes one for each call and reuses it when it retries, so a retried request replays the first message. Pass nextmail.WithIdempotencyKey to make that hold across processes and restarts.
Attachments
invoice, err := os.ReadFile("invoice.pdf")if err != nil { return err} _, err = client.Emails.Send(ctx, nextmail.Body{ "from": "billing@acme.com", "to": "ada@example.com", "subject": "Your September invoice", "text": "The invoice is attached.", "attachments": []nextmail.Body{ {"filename": "invoice.pdf", "content": invoice, "contentType": "application/pdf"}, {"fileId": "file_3f9c2a7b1e4d8f60a5c7b92d"}, },}) return errcontent takes a []byte or an io.Reader, which the client encodes as base64, or text that is base64 already. fileId names a file uploaded with client.Files.Upload, which is how a file larger than 10 MB is sent.
Send later
scheduled, err := client.Emails.Send(ctx, nextmail.Body{ "from": "billing@acme.com", "to": "ada@example.com", "subject": "Your invoice is due tomorrow", "text": "A reminder that the invoice is due tomorrow.", "scheduledAt": time.Now().Add(24 * time.Hour),})if err != nil { return err} if _, err := client.Emails.Reschedule(ctx, scheduled.ID(), time.Now().Add(48*time.Hour)); err != nil { return err} cancelled, err := client.Emails.Cancel(ctx, scheduled.ID())if err != nil { return err} fmt.Println(cancelled.String("status"))scheduledAt takes a time.Time, an ISO 8601 instant or a duration such as PT1H. A time.Time anywhere in a body is sent as an ISO 8601 instant in UTC. A scheduled message can be changed or cancelled until it goes.
Send a batch
result, err := client.Emails.SendBatch(ctx, []nextmail.Body{ {"from": "dispatch@acme.com", "to": "ada@example.com", "subject": "Order AC-4192 has shipped", "text": "It is on its way."}, {"from": "dispatch@acme.com", "to": "grace@example.com", "subject": "Order AC-4193 has shipped", "text": "It is on its way."},})if err != nil { return err} fmt.Println(result.Sent, "sent,", result.Failed, "failed") for _, item := range result.Items { if item.String("status") == "error" { fmt.Println(item.Int("index"), item.Object("error").String("message")) }}A batch holds up to 100 messages and is never all or nothing: a bad address fails its own item and the rest still go. Check Failed and the status of each item instead of relying on an error.
Google Workspace