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

r2arrival

package
v0.40.22 Latest Latest
Warning

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

Go to latest
Published: Nov 2, 2026 License: MIT Imports: 9 Imported by: 0

Documentation

Overview

Package r2arrival sends the one "Your R2 may be here" email.

A user who is waiting for an R2 may tell Rivolt the month they expect it (a month, never a day; engagement_prefs.r2_arrival_month, off until chosen). On the first weekday of that month, at 08:00 in their time zone, they get one email with the connect steps. It goes only to a verified address, only while no vehicle is connected, only when the user has not turned engagement emails off, counts against the engagement budget, and is claimed in engagement_sends under the month, so it is sent at most once across replicas and restarts. It is never sent after its month, and never a second time. Once its email is claimed (sent, failed or already sent) the month is deleted, and a month that has ended is deleted by the sweep: the due list is capped, so finished rows must not crowd later users out, and the month is not kept past its purpose.

Index

Constants

View Source
const (
	SendHour        = 8
	FallbackUTCHour = 14
)

SendHour is the local hour of the send. A user whose browser never stored a time zone gets the same message at FallbackUTCHour, the morning in the Americas, where the first R2s are.

View Source
const (
	OutcomeNoMailer = "no_mailer"
	OutcomeNoSigner = "no_signer"
)

Outcomes beyond Engage's own, as the job's callback names them.

View Source
const Kind = "r2_arrival"

Kind is the engagement_sends kind.

View Source
const UnsubPurpose = "r2-arrival"

UnsubPurpose scopes the signed one-click link in the email to this reminder alone.

Variables

This section is empty.

Functions

func BuildMessage

func BuildMessage(to string, month time.Time, baseURL, token string) email.Message

BuildMessage is the email (DA-approved wording, Oct 31): the connect steps for an R2, how to change or delete the reminder, and a one-click link that deletes it.

func SendTime

func SendTime(month time.Time, loc *time.Location) time.Time

SendTime is the first weekday of month (its first day, UTC) at SendHour in loc.

Types

type Job

type Job struct {
	Source Source
	Engage *engage.Engage
	Mail   Mailer
	// BaseURL is the public origin for the links in the email.
	BaseURL string
	// Signer signs the one-click link. Nil, or a nil result: nothing is sent (no way to opt out, no mail).
	Signer func() *statement.Signer
	// Skip excludes a user (the demo account).
	Skip func(uid uuid.UUID) bool
	Now  func() time.Time
	Log  *slog.Logger
	// OnOutcome is told each send attempt's outcome (engage's, or OutcomeNoSigner).
	OnOutcome func(outcome string)
}

Job is the sweep. Set Source, Engage and Mail; Mail nil counts nothing and sends nothing.

func (*Job) Sweep

func (j *Job) Sweep(ctx context.Context)

Sweep sends the emails due now. Safe on every replica: Engage claims each (user, month).

type Mailer

type Mailer interface {
	Send(ctx context.Context, m email.Message) error
}

Mailer sends an email.

type Source

type Source interface {
	Due(ctx context.Context, from, to time.Time) ([]db.R2ArrivalDue, error)
	StillWanted(ctx context.Context, uid uuid.UUID, month time.Time) (bool, error)
	// Clear deletes the user's month if it is still this one; ClearEnded deletes every month that has ended.
	Clear(ctx context.Context, uid uuid.UUID, month time.Time) error
	ClearEnded(ctx context.Context, now time.Time) (int64, error)
}

Source is the database side.

Jump to

Keyboard shortcuts

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