mail

package
v0.0.0-...-5ea1d0f Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Nov 24, 2025 License: MIT Imports: 11 Imported by: 0

README

Mail Package

Laravel-inspired email system for Conduit-Go with SMTP support.

Features

  • Fluent Message Builder: Chain methods for easy email construction
  • SMTP Driver: Send emails via any SMTP server
  • HTML & Plain Text: Support for both formats
  • Attachments: Add files to emails
  • Multiple Recipients: To, Cc, Bcc support
  • Priority Levels: High, Normal, Low priority
  • Custom Headers: Add custom email headers
  • Log Driver: Development/testing without sending real emails

Quick Start

1. Configure SMTP
import "github.com/biyonik/conduit-go/pkg/mail"

// Gmail example
config := &mail.SMTPConfig{
    Host:     "smtp.gmail.com",
    Port:     587,
    Username: "your@gmail.com",
    Password: "app-password",
    From:     mail.Address{Email: "noreply@app.com", Name: "My App"},
    UseTLS:   true,
}

mailer := mail.NewSMTPMailer(config, logger)
2. Send Email
message := mail.NewMessage().
    To("user@example.com", "John Doe").
    Subject("Welcome to Conduit!").
    Body("Thank you for joining our platform.").
    Html("<h1>Welcome!</h1><p>Thank you for joining.</p>")

err := mailer.Send(message)
if err != nil {
    log.Printf("Failed to send email: %v", err)
}

SMTP Configurations

Mailhog (Development)
config := &mail.SMTPConfig{
    Host: "localhost",
    Port: 1025,
    From: mail.Address{Email: "dev@conduit.local", Name: "Conduit Dev"},
}
Gmail
config := &mail.SMTPConfig{
    Host:     "smtp.gmail.com",
    Port:     587,
    Username: "your@gmail.com",
    Password: "app-password", // Use App Password, not regular password
    UseTLS:   true,
}
SendGrid
config := &mail.SMTPConfig{
    Host:     "smtp.sendgrid.net",
    Port:     587,
    Username: "apikey",
    Password: "your-sendgrid-api-key",
    UseTLS:   true,
}
AWS SES
config := &mail.SMTPConfig{
    Host:     "email-smtp.us-east-1.amazonaws.com",
    Port:     587,
    Username: "your-smtp-username",
    Password: "your-smtp-password",
    UseTLS:   true,
}

Advanced Usage

Multiple Recipients
message := mail.NewMessage().
    To("user1@example.com", "User One").
    To("user2@example.com", "User Two").
    Cc("manager@example.com", "Manager").
    Bcc("admin@example.com", "") // No name
Attachments
message := mail.NewMessage().
    To("user@example.com").
    Subject("Your Invoice").
    Body("Please find attached invoice.").
    Attach("/path/to/invoice.pdf").
    Attach("/path/to/report.xlsx")
Priority
message := mail.NewMessage().
    To("admin@example.com").
    Subject("URGENT: Server Down").
    Body("Server is experiencing issues").
    Priority(mail.PriorityHigh)
Custom Headers
message := mail.NewMessage().
    To("user@example.com").
    Subject("Newsletter").
    Body("...").
    Header("X-Campaign-ID", "summer-2024").
    Header("X-Unsubscribe", "https://app.com/unsubscribe")
Reply-To
message := mail.NewMessage().
    From("noreply@app.com", "My App").
    To("user@example.com").
    ReplyTo("support@app.com", "Support Team").
    Subject("Thank you for contacting us")

Log Driver (Development)

For development/testing, use LogMailer to see emails in logs without sending:

mailer := mail.NewLogMailer(logger)

message := mail.NewMessage().
    To("test@example.com").
    Subject("Test Email").
    Body("This won't be sent, just logged")

mailer.Send(message) // Logs email instead of sending

Integration with Queue System

// In SendEmailJob
func (j *SendEmailJob) Handle() error {
    mailer := j.container.Get("mailer").(mail.Mailer)

    message := mail.NewMessage().
        To(j.To).
        Subject(j.Subject).
        Body(j.Body)

    return mailer.Send(message)
}

Integration with Events

// Listen to user registration event
dispatcher.Listen(events.EventUserRegistered, events.ListenerFunc(func(e events.Event) error {
    user := e.Payload().(*models.User)

    message := mail.NewMessage().
        To(user.Email, user.Name).
        Subject("Welcome!").
        Html(renderTemplate("welcome", user))

    return mailer.Send(message)
}))

Error Handling

message := mail.NewMessage().
    To("user@example.com").
    Subject("Test")

err := mailer.Send(message)
if err != nil {
    // Handle errors
    switch {
    case strings.Contains(err.Error(), "validation failed"):
        log.Println("Invalid message")
    case strings.Contains(err.Error(), "smtp send failed"):
        log.Println("SMTP connection error")
    default:
        log.Printf("Unknown error: %v", err)
    }
}

Best Practices

  1. Use App Passwords: For Gmail, use app-specific passwords, not your main password
  2. Environment Variables: Store SMTP credentials in environment variables
  3. Queue Long Operations: Use SendAsync() or queue for bulk emails
  4. HTML Sanitization: Sanitize user input before adding to HTML body
  5. Rate Limiting: Respect SMTP provider rate limits
  6. Error Logging: Always log email send failures
  7. Test Mode: Use LogMailer in development to avoid sending real emails

Configuration via Environment

config := &mail.SMTPConfig{
    Host:     os.Getenv("MAIL_HOST"),
    Port:     getEnvInt("MAIL_PORT", 587),
    Username: os.Getenv("MAIL_USERNAME"),
    Password: os.Getenv("MAIL_PASSWORD"),
    From: mail.Address{
        Email: os.Getenv("MAIL_FROM_ADDRESS"),
        Name:  os.Getenv("MAIL_FROM_NAME"),
    },
    UseTLS: getEnvBool("MAIL_USE_TLS", true),
}

Testing

func TestEmailSending(t *testing.T) {
    // Use log mailer for testing
    logger := log.New(os.Stdout, "", log.LstdFlags)
    mailer := mail.NewLogMailer(logger)

    message := mail.NewMessage().
        From("test@app.com", "Test").
        To("user@example.com").
        Subject("Test Email").
        Body("Test body")

    err := mailer.Send(message)
    assert.NoError(t, err)
}

Troubleshooting

Gmail: "Username and Password not accepted"
  • Enable "Less secure app access" (not recommended) OR
  • Use App Password: Google Account → Security → App Passwords
Connection Timeout
  • Check firewall rules
  • Verify SMTP port is open (587, 465, or 25)
  • Try different port numbers
TLS Errors
  • For port 587, set UseTLS: true
  • For port 465, use SSL (not TLS)
  • For port 25, usually no encryption

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Address

type Address struct {
	Email string // Email adresi (zorunlu)
	Name  string // İsim (opsiyonel)
}

Address, email adresi ve opsiyonel isim içeren yapıdır.

func (Address) String

func (a Address) String() string

String, Address'i "Name <email@example.com>" formatında döndürür.

type BaseMailer

type BaseMailer struct {
	// contains filtered or unexported fields
}

BaseMailer, tüm mailer implementasyonları için temel yapı.

Bu yapı ortak fonksiyonları sağlar, her driver bu yapıyı embed eder.

func NewBaseMailer

func NewBaseMailer(logger Logger) *BaseMailer

NewBaseMailer, yeni bir BaseMailer oluşturur.

func (*BaseMailer) LogError

func (m *BaseMailer) LogError(message *Message, err error)

LogError, hata oluştuğunda loglar.

func (*BaseMailer) LogSending

func (m *BaseMailer) LogSending(message *Message)

LogSending, gönderim işlemini loglar.

func (*BaseMailer) LogSuccess

func (m *BaseMailer) LogSuccess(message *Message)

LogSuccess, başarılı gönderimi loglar.

func (*BaseMailer) ValidateMessage

func (m *BaseMailer) ValidateMessage(message *Message) error

ValidateMessage, mesajı validate eder.

type LogMailer

type LogMailer struct {
	*BaseMailer
}

LogMailer, email'leri göndermek yerine loglara yazan mailer.

Development ve test ortamında kullanışlıdır. Gerçek email gönderilmez, sadece log'a yazılır.

Kullanım:

mailer := mail.NewLogMailer(logger)
err := mailer.Send(message)

func NewLogMailer

func NewLogMailer(logger Logger) *LogMailer

NewLogMailer, yeni bir LogMailer oluşturur.

Parametre:

  • logger: Log yazımı için logger

Döndürür:

  • *LogMailer: Yeni LogMailer instance

Örnek:

mailer := mail.NewLogMailer(log.Default())

func (*LogMailer) Send

func (m *LogMailer) Send(message *Message) error

Send, email'i loglara yazar (gerçek gönderim yapmaz).

func (*LogMailer) SendAsync

func (m *LogMailer) SendAsync(message *Message) error

SendAsync, log driver için Send() ile aynıdır.

type Logger

type Logger interface {
	Printf(format string, v ...interface{})
	Println(v ...interface{})
}

Logger interface - dependency injection için

type Mailer

type Mailer interface {
	// Send, bir email mesajı gönderir.
	//
	// Parametre:
	//   - message: Gönderilecek mesaj
	//
	// Döndürür:
	//   - error: Gönderim başarısızsa hata
	Send(message *Message) error

	// SendAsync, email'i queue'ya ekleyerek asenkron gönderir.
	// Queue sistemi varsa kullanılır, yoksa senkron Send() çağrılır.
	//
	// Parametre:
	//   - message: Gönderilecek mesaj
	//
	// Döndürür:
	//   - error: Queue'ya ekleme başarısızsa hata
	SendAsync(message *Message) error
}

Mailer, email gönderim interface'i.

Farklı driver'lar (SMTP, Mailgun, SendGrid, SES, vb.) bu interface'i implement ederek sistemle entegre olabilir.

type Message

type Message struct {
	// contains filtered or unexported fields
}

Message, email mesajını temsil eder.

Fluent API ile zincirleme kullanım:

msg := mail.NewMessage().
    To("user@example.com").
    Subject("Hello").
    Body("Welcome!")

func NewMessage

func NewMessage() *Message

NewMessage, yeni bir Message instance'ı oluşturur.

Döndürür:

  • *Message: Yeni message instance

Örnek:

msg := mail.NewMessage()

func (*Message) Attach

func (m *Message) Attach(filePath string) *Message

Attach, dosya ekler.

Parametre:

  • filePath: Eklenecek dosyanın yolu

Döndürür:

  • *Message: Zincirleme için kendi instance'ını döner

Örnek:

msg.Attach("/path/to/document.pdf")
msg.Attach("/path/to/image.jpg")

func (*Message) Bcc

func (m *Message) Bcc(email string, name string) *Message

Bcc, BCC (Blind Carbon Copy) alıcısı ekler.

func (*Message) Body

func (m *Message) Body(body string) *Message

Body, plain text email gövdesini ayarlar.

Parametre:

  • body: Plain text içerik

Döndürür:

  • *Message: Zincirleme için kendi instance'ını döner

Örnek:

msg.Body("Welcome to our platform!\n\nThank you for joining.")

func (*Message) Cc

func (m *Message) Cc(email string, name string) *Message

Cc, CC (Carbon Copy) alıcısı ekler.

func (*Message) From

func (m *Message) From(email string, name string) *Message

From, gönderici adresini ayarlar.

Parametreler:

  • email: Gönderici email adresi
  • name: Gönderici adı (opsiyonel, boş string olabilir)

Döndürür:

  • *Message: Zincirleme için kendi instance'ını döner

Örnek:

msg.From("noreply@conduit.com", "Conduit Team")

func (*Message) GetAttachments

func (m *Message) GetAttachments() []string

GetAttachments, ekleri döndürür.

func (*Message) GetBcc

func (m *Message) GetBcc() []Address

GetBcc, BCC adreslerini döndürür.

func (*Message) GetBody

func (m *Message) GetBody() string

GetBody, plain text gövdeyi döndürür.

func (*Message) GetCc

func (m *Message) GetCc() []Address

GetCc, CC adreslerini döndürür.

func (*Message) GetDate

func (m *Message) GetDate() time.Time

GetDate, tarih döndürür.

func (*Message) GetFrom

func (m *Message) GetFrom() Address

GetFrom, gönderici adresini döndürür.

func (*Message) GetHeaders

func (m *Message) GetHeaders() map[string]string

GetHeaders, özel header'ları döndürür.

func (*Message) GetHtmlBody

func (m *Message) GetHtmlBody() string

GetHtmlBody, HTML gövdeyi döndürür.

func (*Message) GetPriority

func (m *Message) GetPriority() Priority

GetPriority, önceliği döndürür.

func (*Message) GetReplyTo

func (m *Message) GetReplyTo() *Address

GetReplyTo, yanıt adresini döndürür.

func (*Message) GetSubject

func (m *Message) GetSubject() string

GetSubject, konuyu döndürür.

func (*Message) GetTo

func (m *Message) GetTo() []Address

GetTo, alıcı adreslerini döndürür.

func (*Message) Header

func (m *Message) Header(key, value string) *Message

Header, özel header ekler.

Parametreler:

  • key: Header adı
  • value: Header değeri

Döndürür:

  • *Message: Zincirleme için kendi instance'ını döner

Örnek:

msg.Header("X-Custom-Header", "custom-value")
msg.Header("X-Campaign-ID", "summer-2024")

func (*Message) Html

func (m *Message) Html(html string) *Message

Html, HTML email gövdesini ayarlar.

Parametre:

  • html: HTML içerik

Döndürür:

  • *Message: Zincirleme için kendi instance'ını döner

Örnek:

msg.Html("<h1>Welcome!</h1><p>Thank you for joining.</p>")

Güvenlik Notu: HTML içeriği için XSS koruması yapılmaz, güvenilir kaynaklardan HTML kullanın veya template engine kullanın.

func (*Message) Priority

func (m *Message) Priority(priority Priority) *Message

Priority, email önceliğini ayarlar.

Parametre:

  • priority: Öncelik seviyesi (Low, Normal, High)

Döndürür:

  • *Message: Zincirleme için kendi instance'ını döner

Örnek:

msg.Priority(mail.PriorityHigh)

func (*Message) ReplyTo

func (m *Message) ReplyTo(email string, name string) *Message

ReplyTo, yanıt adresi ayarlar.

func (*Message) Subject

func (m *Message) Subject(subject string) *Message

Subject, email konusunu ayarlar.

Parametre:

  • subject: Email konusu

Döndürür:

  • *Message: Zincirleme için kendi instance'ını döner

Örnek:

msg.Subject("Welcome to Conduit!")

func (*Message) To

func (m *Message) To(email string, name string) *Message

To, alıcı adresini ekler.

Parametreler:

  • email: Alıcı email adresi
  • name: Alıcı adı (opsiyonel)

Döndürür:

  • *Message: Zincirleme için kendi instance'ını döner

Örnek:

msg.To("user@example.com", "John Doe")
msg.To("admin@example.com", "") // İsim olmadan

func (*Message) Validate

func (m *Message) Validate() error

Validate, message'ın geçerli olup olmadığını kontrol eder.

Döndürür:

  • error: Geçersizse hata, geçerliyse nil

Kontroller: - From adresi dolu olmalı - En az bir To adresi olmalı - Subject dolu olmalı - Body veya HtmlBody dolu olmalı

type Priority

type Priority int

Priority, email öncelik seviyesi.

const (
	PriorityLow    Priority = 1
	PriorityNormal Priority = 3
	PriorityHigh   Priority = 5
)

type SMTPConfig

type SMTPConfig struct {
	Host     string        // SMTP sunucu adresi (örn: smtp.gmail.com)
	Port     int           // SMTP port (25, 587, 465)
	Username string        // SMTP kullanıcı adı
	Password string        // SMTP şifre
	From     Address       // Varsayılan gönderici adresi
	UseTLS   bool          // TLS kullanılsın mı (587 port için true)
	Timeout  time.Duration // Bağlantı timeout süresi (varsayılan: 30s)

}

SMTPConfig, SMTP bağlantı ayarlarını içerir.

type SMTPMailer

type SMTPMailer struct {
	*BaseMailer
	// contains filtered or unexported fields
}

SMTPMailer, SMTP ile email gönderen mailer.

func NewSMTPMailer

func NewSMTPMailer(config *SMTPConfig, logger Logger) *SMTPMailer

NewSMTPMailer, yeni bir SMTP mailer oluşturur.

Parametreler:

  • config: SMTP konfigürasyonu
  • logger: Logger instance

Döndürür:

  • *SMTPMailer: Yeni SMTP mailer

Örnek (Gmail):

config := &mail.SMTPConfig{
    Host:     "smtp.gmail.com",
    Port:     587,
    Username: "your@gmail.com",
    Password: "app-password",
    UseTLS:   true,
}
mailer := mail.NewSMTPMailer(config, logger)

Örnek (Mailhog - Development):

config := &mail.SMTPConfig{
    Host:     "localhost",
    Port:     1025,
    From:     mail.Address{Email: "dev@conduit.local"},
}
mailer := mail.NewSMTPMailer(config, logger)

func (*SMTPMailer) Send

func (m *SMTPMailer) Send(message *Message) error

Send, email'i SMTP üzerinden gönderir.

func (*SMTPMailer) SendAsync

func (m *SMTPMailer) SendAsync(message *Message) error

SendAsync, queue yoksa senkron gönderir. Queue integration yapıldığında bu metod güncellenecek.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL