Documentation
¶
Overview ¶
Package mailer provides a robust and concurrent email sending service for Go applications.
It features a queue-based system (`MailService`) that utilizes a pool of worker goroutines to send emails asynchronously. This allows applications to enqueue emails quickly without blocking on the actual sending process.
Key Features:
- Concurrent email sending via a configurable worker pool.
- Buffered queue for email content (`MailContent`).
- Graceful shutdown using context cancellation and wait groups.
- Pluggable backend architecture via the `MailerService` interface.
- Includes a standard SMTP implementation (`MailerSMTP`).
- Provides a builder (`MailContentBuilder`) for validated email content creation.
Usage typically involves:
- Configuring a `MailerService` implementation (e.g., `NewMailerSMTP`).
- Configuring the main `MailService` with the desired worker count and the chosen mailer backend.
- Starting the `MailService` with a context.
- Enqueuing `MailContent` instances using the `Enqueue` method.
- Stopping the service gracefully or relying on context cancellation for shutdown.
See the `ExampleMailService_Enqueue` function in the tests for a practical usage demonstration.
Index ¶
- Constants
- type MailContent
- type MailContentBuilder
- func (b *MailContentBuilder) Build() (MailContent, error)
- func (b *MailContentBuilder) WithBody(body string) *MailContentBuilder
- func (b *MailContentBuilder) WithFromAddress(address string) *MailContentBuilder
- func (b *MailContentBuilder) WithFromName(name string) *MailContentBuilder
- func (b *MailContentBuilder) WithMimeType(mimeType MimeType) *MailContentBuilder
- func (b *MailContentBuilder) WithMimeTypeAsString(mimeType string) *MailContentBuilder
- func (b *MailContentBuilder) WithSubject(subject string) *MailContentBuilder
- func (b *MailContentBuilder) WithToAddress(address string) *MailContentBuilder
- func (b *MailContentBuilder) WithToName(name string) *MailContentBuilder
- type MailQueueError
- type MailQueueService
- type MailService
- type MailServiceConfig
- type MailerError
- type MailerSMTP
- type MailerSMTPConf
- type MailerService
- type MimeType
Examples ¶
Constants ¶
const ( ValidMinFromNameLength = 1 ValidMaxFromNameLength = 100 ValidMinFromAddressLength = 5 ValidMaxFromAddressLength = 50 ValidMinToNameLength = 1 ValidMaxToNameLength = 100 ValidMinToAddressLength = 5 ValidMaxToAddressLength = 50 ValidMimeType = "text/plain|text/html" ValidMinSubjectLength = 1 ValidMaxSubjectLength = 255 ValidMinBodyLength = 1 ValidMaxBodyLength = 20000 )
const ( ValidMaxWorkerCount = 100 ValidMinWorkerCount = 1 )
const ( ValidMinSMTPHostLength = 5 ValidMaxSMTPHostLength = 100 ValidSMTPPorts = "25|465|587|1025|8025" ValidMinUsernameLength = 1 ValidMaxUsernameLength = 100 ValidMinPasswordLength = 3 ValidMaxPasswordLength = 100 )
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type MailContent ¶
type MailContent struct {
// contains filtered or unexported fields
}
MailContent represents the content of an email.
type MailContentBuilder ¶
type MailContentBuilder struct {
// contains filtered or unexported fields
}
func NewMailContentBuilder ¶ added in v0.0.3
func NewMailContentBuilder() *MailContentBuilder
func (*MailContentBuilder) Build ¶
func (b *MailContentBuilder) Build() (MailContent, error)
func (*MailContentBuilder) WithBody ¶
func (b *MailContentBuilder) WithBody(body string) *MailContentBuilder
func (*MailContentBuilder) WithFromAddress ¶
func (b *MailContentBuilder) WithFromAddress(address string) *MailContentBuilder
func (*MailContentBuilder) WithFromName ¶
func (b *MailContentBuilder) WithFromName(name string) *MailContentBuilder
func (*MailContentBuilder) WithMimeType ¶
func (b *MailContentBuilder) WithMimeType(mimeType MimeType) *MailContentBuilder
func (*MailContentBuilder) WithMimeTypeAsString ¶ added in v0.0.2
func (b *MailContentBuilder) WithMimeTypeAsString(mimeType string) *MailContentBuilder
func (*MailContentBuilder) WithSubject ¶
func (b *MailContentBuilder) WithSubject(subject string) *MailContentBuilder
func (*MailContentBuilder) WithToAddress ¶
func (b *MailContentBuilder) WithToAddress(address string) *MailContentBuilder
func (*MailContentBuilder) WithToName ¶
func (b *MailContentBuilder) WithToName(name string) *MailContentBuilder
type MailQueueError ¶
type MailQueueError struct {
Message string
}
func (*MailQueueError) Error ¶
func (e *MailQueueError) Error() string
type MailQueueService ¶
type MailQueueService interface {
Enqueue(content MailContent) error
}
type MailService ¶
type MailService struct {
// contains filtered or unexported fields
}
func NewMailService ¶
func NewMailService(conf *MailServiceConfig) (*MailService, error)
func (*MailService) Enqueue ¶
func (ref *MailService) Enqueue(content MailContent) error
Enqueue adds mail content to the queue. It returns an error if the service's context is cancelled during the attempt.
Example ¶
ExampleMailService_Enqueue demonstrates how to create a MailService, enqueue an email, and have it processed by a mock mailer.
// Use a mock mailer for demonstration purposes
mockMailer := &MockMailerService{}
ctx, cancel := context.WithCancel(context.Background())
defer cancel() // Ensure context is cancelled eventually
// Configure the mail service
config := &MailServiceConfig{
Ctx: ctx,
WorkerCount: 1, // One worker is sufficient for the example
Mailer: mockMailer,
}
service, err := NewMailService(config)
if err != nil {
fmt.Printf("Error creating service: %v\n", err)
return
}
service.Start()
// Create email content using the builder
content, err := (&MailContentBuilder{}).
WithFromName("Example Sender").
WithFromAddress("sender@example.net").
WithToName("Example Recipient").
WithToAddress("recipient@example.net").
WithMimeType("text/plain").
WithSubject("Example Subject").
WithBody("This is the example email body.").
Build()
if err != nil {
fmt.Printf("Error building content: %v\n", err)
return
}
// Enqueue the email
err = service.Enqueue(content)
if err != nil {
fmt.Printf("Error enqueuing email: %v\n", err)
// Don't return here, allow Stop to run for cleanup
}
// Stop the service gracefully. This ensures the enqueued item is processed
// by the worker before the example finishes.
service.Stop()
// Check if the mock mailer received the email
if mockMailer.Count() > 0 {
// Accessing unexported fields like subject directly isn't possible here.
// We'll print a confirmation message based on the count.
// In a real test, you might check mockMailer.SentMail[0].subject if it were exported
// or add a method to MockMailerService to get sent subjects.
fmt.Printf("Mock mailer received %d email(s).\n", mockMailer.Count())
} else {
fmt.Println("Mock mailer did not receive the email.")
}
Output: Mock mailer received 1 email(s).
func (*MailService) Start ¶
func (ref *MailService) Start()
Start initializes the worker goroutines that will process the mail queue. Each worker will listen on the content channel for new mail content to process. The workers will run concurrently, and the number of workers is determined by the WorkerCount field. The context provided in the configuration is used to manage the lifecycle of the workers. If the context is cancelled, all workers will stop processing and exit gracefully. The workers will log their status and any errors encountered during the email sending process.
func (*MailService) Stop ¶
func (ref *MailService) Stop()
Stop closes the content channel and waits for all workers to finish processing.
func (*MailService) Wait ¶
func (ref *MailService) Wait()
Wait blocks until all worker goroutines have exited. Useful if you cancel the context and want to ensure workers stopped without necessarily closing the channel via Stop().
type MailServiceConfig ¶
type MailServiceConfig struct {
Ctx context.Context
// WorkerCount is the number of concurrent workers to process the mail queue.
// It must be between 1 and 100.
WorkerCount int
// Timeout is the duration for which the service will wait for a worker to finish processing before timing out.
// This is currently not used in the core service logic but can be implemented in the future.
Timeout time.Duration
// Mailer is the service responsible for sending emails.
// It must not be nil.
Mailer MailerService
}
type MailerError ¶
type MailerError struct {
Message string
}
MailerError is a custom error type for mailer-related errors. It implements the error interface.
func (*MailerError) Error ¶
func (e *MailerError) Error() string
Error implements the error interface for MailerError.
type MailerSMTP ¶
type MailerSMTP struct {
// contains filtered or unexported fields
}
func NewMailerSMTP ¶
func NewMailerSMTP(conf MailerSMTPConf) (*MailerSMTP, error)
func (*MailerSMTP) Send ¶
func (m *MailerSMTP) Send(ctx context.Context, content MailContent) error
type MailerSMTPConf ¶
type MailerSMTPConf struct {
// SMTPHost is the hostname of the SMTP server (5-100 chars). *Required*.
// It must be a valid hostname or IP address.
SMTPHost string
// SMTPPort is the port of the SMTP server (must be 25, 465, or 587). *Required*.
// Valid ports are 25 (SMTP), 465 (SMTPS), 587 (Submission), 1025, and 8025.
// Ports 1025 and 8025 are less common and may be used in specific configurations, such as testing or non-standard setups.
SMTPPort int
// Username is the SMTP username for authentication (1-100 chars). *Required*.
Username string
// Password is the SMTP password for authentication (3-100 chars). *Required*.
// It should be kept secret and not logged or exposed.
Password string
}
type MailerService ¶
type MailerService interface {
Send(ctx context.Context, content MailContent) error
}
MailerService is an interface must be implemented by any mailer service that is used to send emails.