Help us shape the future of Go! Take the 2026 Go Developer Survey

email

package
v1.21.2 Latest Latest
Warning

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

Go to latest
Published: Oct 27, 2026 License: GPL-3.0 Imports: 22 Imported by: 0

Documentation

Overview

Package email holds the queue handlers that send email: single notifications (verification codes, expiry, traffic and maintenance notices, custom mail) and the marketing campaigns administrators run in batches, together with the workers that pace a campaign and record its progress.

Index

Constants

This section is empty.

Variables

View Source
var ErrTaskNotActive = errors.New("batch email task is no longer active")

ErrTaskNotActive stops a worker whose task an administrator cancelled or another run finished; the queue shell treats it as done, not failed.

Functions

This section is empty.

Types

type BatchEmailHandler added in v1.21.0

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

BatchEmailHandler runs a marketing email campaign, the batch task an administrator created. The task row in the platform kernel's bookkeeping carries the campaign and its progress, so a campaign that reaches the daily sending limit continues from a follow-up task the next day, one that runs out of its run budget continues from a follow-up task at once, and a retried delivery resumes where the last run stopped.

func NewBatchEmailHandler added in v1.21.0

func NewBatchEmailHandler(deps Dependencies) *BatchEmailHandler

NewBatchEmailHandler builds the handler over the task bookkeeping, the message log, the queue and the runtime email settings.

func (*BatchEmailHandler) ProcessTask added in v1.21.0

func (h *BatchEmailHandler) ProcessTask(ctx context.Context, task *asynq.Task) error

type DailyLimitReached

type DailyLimitReached struct {
	NextAt time.Time
}

DailyLimitReached asks the queue shell to persist a continuation for the next civil day instead of keeping one queue worker asleep for hours.

func (*DailyLimitReached) Error

func (e *DailyLimitReached) Error() string

type Dependencies

type Dependencies struct {
	Tasks    repository.TaskRepo
	Logs     repository.LogRepo
	Queue    TaskScheduler
	Email    func() config.EmailConfig
	SiteName func() string
	// Recipients re-resolves a campaign's audience when a run starts, so
	// accounts deleted since the campaign was created get no email; nil
	// sends to the recorded recipients as they are.
	Recipients RecipientResolver
}

Dependencies are the email tasks': the batch tasks' bookkeeping and the message log (the platform kernel's), the queue, the runtime settings and the identity facade's recipient selection.

type ErrorInfo

type ErrorInfo struct {
	Error string `json:"error"`
	Email string `json:"email"`
	Time  int64  `json:"time"`
}

ErrorInfo is one failed delivery of a campaign, as the task records it.

type MessageLogStore

type MessageLogStore interface {
	Insert(ctx context.Context, data *logEntity.SystemLog) error
	Update(ctx context.Context, data *logEntity.SystemLog) error
}

MessageLogStore is the message log a worker audits each delivery in.

type RecipientResolver added in v1.21.0

type RecipientResolver interface {
	QueryEmailRecipients(ctx context.Context, filter *user.EmailRecipientFilter) ([]string, error)
}

RecipientResolver selects the accounts a campaign scope reaches today; the identity facade provides it.

type RunBudgetExhausted added in v1.21.0

type RunBudgetExhausted struct {
	Sent     uint64
	ResumeAt time.Time
}

RunBudgetExhausted asks the queue shell to continue the campaign from a follow-up task right away: the run's deadline (the queue's task timeout) is too close to pace another delivery, so the worker stopped after the last recipient it recorded instead of being cut off mid-run and retried with a backoff. Sent is the recipients delivered so far, the position the continuation resumes from; ResumeAt keeps the campaign's pacing across the two runs.

func (*RunBudgetExhausted) Error added in v1.21.0

func (e *RunBudgetExhausted) Error() string

type SendEmailHandler added in v1.21.0

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

SendEmailHandler sends one notification email. The body and subject come from the operator-configured templates of the notification type. The attempt is written to the message log before the provider call and finalized after it; once the provider was called the task is not retried, even on an error, because a failed call may still have delivered the mail.

func NewSendEmailHandler added in v1.21.0

func NewSendEmailHandler(deps Dependencies) *SendEmailHandler

NewSendEmailHandler builds the handler over the message log and the runtime email settings.

func (*SendEmailHandler) ProcessTask added in v1.21.0

func (h *SendEmailHandler) ProcessTask(ctx context.Context, task *asynq.Task) error

type TaskScheduler

type TaskScheduler interface {
	EnqueueContext(ctx context.Context, task *asynq.Task, opts ...asynq.Option) (*asynq.TaskInfo, error)
}

TaskScheduler enqueues the follow-up task a campaign continues from once it reached the daily sending limit or the end of its run budget; the asynq client provides it.

type TaskStore

type TaskStore interface {
	FindOneByType(ctx context.Context, id int64, typ task.Type) (*task.Task, error)
	UpdateActive(ctx context.Context, data *task.Task) (bool, error)
	UpdateActiveProgress(ctx context.Context, data *task.Task) (bool, error)
	UpdateActiveProgressWithError(ctx context.Context, data *task.Task, taskError *task.TaskError) (bool, error)
	InsertError(ctx context.Context, data *task.TaskError) error
	FindErrors(ctx context.Context, taskIDs []int64) ([]*task.TaskError, error)
}

TaskStore is the minimal task repository interface needed by the batch-email worker.

type Worker

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

Worker sends one campaign to its recipients, one at a time, recording the progress and every failure on the task so a later run resumes after the last recipient sent.

func NewWorker

func NewWorker(ctx context.Context, id int64, tasks TaskStore, sender mail.Sender, options ...WorkerOption) *Worker

NewWorker builds the worker of task id; ctx bounds the run.

func (*Worker) GetID

func (w *Worker) GetID() int64

GetID returns the id of the task the worker runs.

func (*Worker) Start

func (w *Worker) Start() error

Start processes a batch-email task until completion, cancellation or the end of the run's budget, which a follow-up task continues from.

type WorkerManager

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

WorkerManager owns asynchronous batch-email workers. It is an application worker, so it belongs in internal rather than the reusable email package.

var (
	// Manager is the process's worker manager, created by the first
	// NewWorkerManager call.
	Manager *WorkerManager
)

func NewWorkerManager

func NewWorkerManager() *WorkerManager

NewWorkerManager returns the process's worker manager, creating it on the first call.

func (*WorkerManager) GetWorker

func (m *WorkerManager) GetWorker(id int64) *Worker

GetWorker returns the worker currently assigned to id.

func (*WorkerManager) RemoveWorker

func (m *WorkerManager) RemoveWorker(id int64)

RemoveWorker cancels and removes the worker assigned to id.

func (*WorkerManager) RunWorker

func (m *WorkerManager) RunWorker(ctx context.Context, id int64, tasks TaskStore, sender mail.Sender, options ...WorkerOption) error

RunWorker keeps queue acknowledgement coupled to the actual campaign run. A duplicate delivery in the same process is harmless: the existing worker remains authoritative for that database task.

type WorkerOption

type WorkerOption func(*Worker)

WorkerOption configures a Worker.

func WithMessageLogs

func WithMessageLogs(logs MessageLogStore, platform string) WorkerOption

WithMessageLogs audits each delivery in logs under the provider platform.

func WithRecipientResolver added in v1.21.0

func WithRecipientResolver(recipients RecipientResolver) WorkerOption

WithRecipientResolver re-checks the campaign's recipients against the accounts its scope selects when the run starts, so an account deleted or no longer eligible since the campaign was created is skipped.

Jump to

Keyboard shortcuts

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