Examples
Email via API (Mailgun / SendGrid)
A complete minimal program that sends email via an API-based driver.
This is the recommended production setup — API-based driver instead of SMTP, so it works on any cloud host (see SMTP Port Blocking).
Examples live in their own Go module
The runnable version of this program is in _examples/email-api of the
repository. The _examples/ directory is a separate Go module, so the
library itself keeps zero third-party dependencies. Run it from there:
cd _examples && go run ./email-api.
Mailgun variant
package main
import (
"context"
"log"
"os"
"time"
notification "github.com/gopackx/go-notification"
"github.com/gopackx/go-notification/channel/mail"
"github.com/gopackx/go-notification/channel/mail/mailgun"
)
type User struct {
ID string
Name string
Email string
}
func (u User) GetID() string { return u.ID }
func (u User) RouteNotificationFor(channel string) string {
if channel == "mail" {
return u.Email
}
return ""
}
type PasswordReset struct {
ResetURL string
}
func (n PasswordReset) Via(_ notification.Notifiable) []string { return []string{"mail"} }
func (n PasswordReset) ToMail(notifiable notification.Notifiable) *mail.Message {
u := notifiable.(User)
return mail.NewMessage().
SetSubject("Reset your password").
SetGreeting("Hi " + u.Name + ",").
Line("We received a request to reset your password.").
Action("Reset password", n.ResetURL).
Line("This link expires in 30 minutes. If you didn't request this, ignore this email.")
}
func main() {
notifier := notification.New(notification.Config{})
notifier.RegisterChannel(mailgun.New(mailgun.Config{
Domain: "mg.example.com",
APIKey: os.Getenv("MAILGUN_API_KEY"),
From: mail.Address{Name: "Acme", Address: "no-reply@example.com"},
}))
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()
user := User{ID: "1", Name: "Dani", Email: "dani@example.com"}
if err := notifier.Send(ctx, user, PasswordReset{
ResetURL: "https://app.example.com/reset?token=abc",
}); err != nil {
log.Fatal(err)
}
notifier.Close()
}SendGrid variant
Swap the channel registration only — notification code is identical.
import (
"github.com/gopackx/go-notification/channel/mail"
"github.com/gopackx/go-notification/channel/mail/sendgrid"
)
notifier.RegisterChannel(sendgrid.New(sendgrid.Config{
APIKey: os.Getenv("SENDGRID_API_KEY"),
From: mail.Address{Name: "Acme", Address: "no-reply@example.com"},
}))Env setup
# Mailgun
export MAILGUN_API_KEY=key-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
# or SendGrid
export SENDGRID_API_KEY=SG.xxxxxxxxxxxxxxxxxxxxxx.xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
# from a clone of the repository
cd _examples && go run ./email-apiDeliverability checklist
If your mail lands in spam:
- Verify SPF, DKIM, and DMARC on your sending domain. Both Mailgun and SendGrid walk you through this in their dashboards — don't skip any record.
- Use a dedicated subdomain for transactional mail (e.g.
mg.example.comormail.example.com). Reputation on that subdomain is independent of your main domain's web traffic. - Warm up a new sending domain — start with low volume for the first 2–4 weeks and ramp gradually.
- Handle bounces and complaints. When the provider reports a hard bounce, mark that address as undeliverable in your DB and stop sending to it.
- Avoid marketing-looking subject lines for transactional mail — words like "FREE", "GUARANTEED", all-caps, or lots of emojis can trip spam filters.
Testing locally without sending
Replace the driver with Mailtrap in sandbox mode:
import (
"strconv"
"github.com/gopackx/go-notification/channel/mail"
"github.com/gopackx/go-notification/channel/mail/mailtrap"
)
if os.Getenv("APP_ENV") == "production" {
notifier.RegisterChannel(mailgun.New(mailgun.Config{ /* ... */ }))
} else {
inboxID, _ := strconv.Atoi(os.Getenv("MAILTRAP_INBOX_ID"))
notifier.RegisterChannel(mailtrap.New(mailtrap.Config{
Sandbox: true,
APIToken: os.Getenv("MAILTRAP_API_TOKEN"),
InboxID: inboxID,
From: mail.Address{Name: "Dev", Address: "dev@example.com"},
}))
}Mail in dev goes to a Mailtrap inbox; in prod, to real inboxes. No code change between environments.