mail

package
v0.2.22 Latest Latest
Warning

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

Go to latest
Published: Jul 18, 2026 License: MPL-2.0 Imports: 36 Imported by: 0

Documentation

Overview

Package mail implements the bundled txco://sendmail op: it reads the `_sendmail` envelope contract a rule assembled, renders an email (a shell template wrapping the body — the bundled default, or a caller-supplied `_sendmail.templates.html`), enforces the per-tenant campaign at-most-once guard, verifies the From domain, submits to a relay, and emits a usage line. The common case is to/subject/body/from; attachments and policy caps are later phases (see internal docs/todo-sendmail.md).

Index

Constants

This section is empty.

Variables

View Source
var ErrNoRelay = errors.New("sendmail: no mail relay configured (set --mail-relay-addr / TXCO_MAIL_RELAY_ADDR)")

ErrNoRelay is returned by the op when no relay is configured.

Functions

This section is empty.

Types

type Config

type Config struct {
	RelayAddr     string
	RelayTLS      string // "none" | "starttls"
	DialTimeout   time.Duration
	MaxRecipients int
	RateLimits    string // per-tenant send caps, e.g. "100/2m,200/4h"; empty disables
}

Config carries the relay + limits resolved from chassis config.

type Mailer

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

Mailer is the txco://sendmail handler with its injected deps. db is the REAL, writable runtime *sql.DB (stable — dbcache only swaps its in-memory snapshot, not this handle), used for the campaign claim and the From-domain check. usage is nil-safe. submit is injectable (real SMTP in prod, a fake in tests).

func NewMailer

func NewMailer(db *sql.DB, dialect registry.Dialect, snap func() *sql.DB, u usage.Sink, log *zap.Logger, cfg Config) *Mailer

NewMailer builds a Mailer. db must be the real runtime DB (e.g. pu.RuntimeDB) and dialect its DB dialect (pu.RuntimeDialect) so the runtime queries rebind for Postgres. snap is the dbcache mirror snapshot getter (pu.Dbc.Snapshot) used for the per-send verification READS — pass the method value, never a captured *sql.DB (Reload swaps the handle); nil falls back to db. usage/log may be nil.

func (*Mailer) Relay added in v0.2.19

func (m *Mailer) Relay(ctx context.Context, tenant, source string, in []byte) (event.Payload, error)

Relay is the txco://relay op body — the `.forward` primitive. Unlike Send it does NOT re-compose or re-DKIM-sign: it ships the ORIGINAL RFC 5322 bytes (`_relay.raw`, base64, straight from `@lmtp.msg.raw`) to a new recipient untouched, so the sender's surviving DKIM signature keeps DMARC aligned to their domain and attachments are preserved. It just rewrites the SMTP envelope: MAIL FROM = `_relay.envelope_from` (a return-path the tenant owns, so SPF aligns and bounces route somewhere catchable), RCPT = `_relay.to`.

source is the request's PINNED originating inlet (processor.SourceScope) — the trusted answer to "which inlet started this", captured at first Run, NOT the mutable `_txc.src` envelope field. Because relay ships arbitrary bytes out under a verified return-path (far more dangerous than sendmail, which forces a verified From + signs), it MUST run only from the inbound-mail path: a coerced web/other pipeline could otherwise relay attacker-supplied bytes as a spam cannon riding the domain's reputation. So the first thing Relay does is refuse unless source == "lmtp".

tenant is the PINNED request tenant (processor.TenantScope), used for the defense-in-depth envelope_from-domain-verified check and the campaign guard.

func (*Mailer) Send

func (m *Mailer) Send(ctx context.Context, tenant string, in []byte) (event.Payload, error)

Send is the op body. tenant is the PINNED request tenant (resolved by the caller from the trusted context, NOT the mutable envelope) — load-bearing for the campaign key and the From-domain anti-spoof check.

type SubmitFunc

type SubmitFunc func(ctx context.Context, from string, rcpts []string, msg []byte) error

SubmitFunc hands one rendered RFC 5322 message to the relay for `from` → `rcpts` (the envelope recipients: the To recipient plus any Cc/Bcc). Injectable so tests can substitute a fake.

Jump to

Keyboard shortcuts

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