A high-performance Go wrapper for gopkg.in/gomail.v2 with connection pooling, persistent connections, and bulk sending capabilities.
- Persistent Connections: Reuse SMTP connections across multiple emails
- Connection Pooling: Thread-safe connection pool for concurrent email sending
- Bulk Sending: Send multiple emails efficiently with a single connection
- Template Support: HTML and plain text templates with embedded FS support
- Buffer Pooling: Optimized memory usage with sync.Pool for template rendering
- Attachments: Support for file attachments with custom names
go get github.com/openframebox/gomailmailer, err := gomail.New(&gomail.Config{
SMTPHost: "localhost",
SMTPPort: 1025,
SMTPUser: "user",
SMTPPass: "password",
TemplateFS: templateFS, // embed.FS
})
if err != nil {
log.Fatal(err)
}
mail := &gomail.Mail{
Subject: "Hello",
From: gomail.Address{Name: "Sender", Email: "sender@example.com"},
To: []gomail.Address{{Name: "User", Email: "user@example.com"}},
Template: "Welcome {{.name}}!",
Data: map[string]any{"name": "John"},
}
err = mailer.Send(context.Background(), mail)// Open persistent connection
sender, err := mailer.Dial()
if err != nil {
log.Fatal(err)
}
defer sender.Close()
// Send multiple emails through same connection
for i := 0; i < 100; i++ {
mail := &gomail.Mail{
Subject: "Email " + strconv.Itoa(i),
From: gomail.Address{Email: "sender@example.com"},
To: []gomail.Address{{Email: "user@example.com"}},
Template: "Message {{.id}}",
Data: map[string]any{"id": i},
}
if err := sender.Send(context.Background(), mail); err != nil {
log.Fatal(err)
}
}// Prepare batch
mails := make([]*gomail.Mail, 100)
for i := 0; i < 100; i++ {
mails[i] = &gomail.Mail{
Subject: "Bulk Email",
From: gomail.Address{Email: "sender@example.com"},
To: []gomail.Address{{Email: "user@example.com"}},
Template: "Message {{.id}}",
Data: map[string]any{"id": i},
}
}
// Send all with single connection
err = mailer.SendBulk(context.Background(), mails)// Create pool with max 10 connections
pool := mailer.NewPool(gomail.PoolConfig{
MaxSize: 10,
})
defer pool.Close()
// Send emails concurrently
var wg sync.WaitGroup
for i := 0; i < 1000; i++ {
wg.Add(1)
go func(id int) {
defer wg.Done()
mail := &gomail.Mail{
Subject: "Concurrent Email",
From: gomail.Address{Email: "sender@example.com"},
To: []gomail.Address{{Email: "user@example.com"}},
Template: "Message {{.id}}",
Data: map[string]any{"id": id},
}
if err := pool.Send(context.Background(), mail); err != nil {
log.Printf("error: %v", err)
}
}(i)
}
wg.Wait()config := &gomail.Config{
SMTPHost: "smtp.gmail.com", // SMTP server host
SMTPPort: 587, // SMTP server port
SMTPUser: "user@gmail.com", // SMTP username
SMTPPass: "password", // SMTP password
UseTLS: true, // Use STARTTLS
UseSSL: false, // Use SSL/TLS (port 465)
TemplateFS: templateFS, // Template filesystem
}poolConfig := gomail.PoolConfig{
MaxSize: 10, // Max connections in pool
IdleTimeout: 5 * time.Minute, // Idle connection timeout
MaxLifetime: 30 * time.Minute, // Max connection lifetime
}Templates support both HTML and plain text formats:
templates/
├── welcome.html # HTML version
└── welcome.txt # Plain text version
//go:embed templates/*
var templateFS embed.FS
mailer, err := gomail.New(&gomail.Config{
// ... other config
TemplateFS: templateFS,
})
mail := &gomail.Mail{
Template: "welcome", // Uses welcome.html and welcome.txt
Data: map[string]any{"name": "John", "code": "ABC123"},
}Inline templates are also supported:
mail := &gomail.Mail{
Template: "Hello {{.name}}, your code is {{.code}}",
Data: map[string]any{"name": "John", "code": "ABC123"},
}customName := "report.pdf"
mail := &gomail.Mail{
// ... other fields
Attachments: []gomail.Attachment{
{Path: "/path/to/file.pdf", Name: &customName}, // Custom name
{Path: "/path/to/data.csv"}, // Original name
},
}Run benchmarks with mailpit running locally:
# Start mailpit
docker run -p 1025:1025 -p 8025:8025 axllent/mailpit
# Run benchmarks
go test -bench=. -benchmem -benchtime=10sExpected results (local mailpit):
BenchmarkSend 100 120ms/op # Original
BenchmarkSendWithPersistentConnection 1000 12ms/op # 10x faster
BenchmarkSendBulk100 50 250ms/op # 48x faster
BenchmarkPool 500 25ms/op # 5x faster
BenchmarkPoolParallel 2000 10ms/op # 12x faster
mailer.Send(ctx, mail)sender, _ := mailer.Dial()
defer sender.Close()
for _, mail := range mails {
sender.Send(ctx, mail)
}mailer.SendBulk(ctx, mails)pool := mailer.NewPool(gomail.PoolConfig{MaxSize: 10})
defer pool.Close()
pool.Send(ctx, mail) // Thread-safeMIT License
Pull requests are welcome! For major changes, please open an issue first.