email

package
v0.1.0 Latest Latest
Warning

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

Go to latest
Published: May 10, 2026 License: AGPL-3.0 Imports: 12 Imported by: 0

Documentation

Overview

Package email is the transactional-email layer for the auth surface.

Concrete implementations:

  • Stdout — writes a human-readable dump of every email to a writer. Used in tests and as the dev default when no SMTP is configured.
  • MailHog (any plain SMTP server) — used by `make dev-email` for local end-to-end testing.
  • Postmark — the prod implementation. Skeleton lives in postmark.go; full credentials wired by S35 deploy work.

Templates live alongside the auth handlers under templates/email/ and have HTML + plaintext variants. Senders MUST send both.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Branding

type Branding struct {
	SiteName string // e.g. "shithub"
	BaseURL  string // e.g. "https://shithub.example" — no trailing slash
	From     string // e.g. "shithub <noreply@shithub.example>"
}

Branding is the per-instance customization for outgoing emails.

type Message

type Message struct {
	From    string
	To      string
	Subject string
	HTML    string
	Text    string
}

Message is the unit a Sender ships. Both HTML and Text are required — every transactional email shithub sends must work in plain-text clients.

func NoticeMessage

func NoticeMessage(b Branding, to, username, kind string) (Message, error)

NoticeMessage builds a 2FA / security state-change notice for kind. The kind names match audit-log Action values where applicable.

func ResetMessage

func ResetMessage(b Branding, to, token string) (Message, error)

ResetMessage builds the password-reset message.

func SSHKeyAddedMessage

func SSHKeyAddedMessage(b Branding, to, username, title, fingerprint, ip string) (Message, error)

SSHKeyAddedMessage builds the new-key notification email. Sent on successful key add — title/fingerprint/IP help the user spot a compromise quickly.

func TokenCreatedMessage

func TokenCreatedMessage(b Branding, to, username, name, prefix, ip string) (Message, error)

TokenCreatedMessage notifies the user that a new PAT was minted on their account. Helps detect compromise — a token they didn't make is a big red flag.

func VerifyMessage

func VerifyMessage(b Branding, to, username, token string) (Message, error)

VerifyMessage builds the email-verification message.

type PostmarkSender

type PostmarkSender struct {
	ServerToken string // X-Postmark-Server-Token
	From        string // verified sender address
	HTTP        *http.Client
}

PostmarkSender posts messages to the Postmark transactional API. The integration is intentionally thin: one HTTP POST per message, no templates, no batching. Postmark's templating story stays out-of-band.

func (*PostmarkSender) Send

func (p *PostmarkSender) Send(ctx context.Context, m Message) error

Send implements Sender.

type SMTPSender

type SMTPSender struct {
	Addr     string // host:port
	From     string // default From when Message.From is empty
	Username string // optional
	Password string // optional
	UseTLS   bool   // STARTTLS upgrade after EHLO
}

SMTPSender ships messages through a plain SMTP server. Used for MailHog locally. SMTP credentials are optional (MailHog accepts none).

func (*SMTPSender) Send

func (s *SMTPSender) Send(_ context.Context, m Message) error

Send implements Sender. Builds a multipart/alternative body so MUAs can pick the variant they prefer.

The SMTP envelope sender is the bare address — `MAIL FROM:<...>` per RFC 5321 forbids nested angle brackets, so a configured `From` like `shithub <noreply@shithub.local>` only goes in the message header. The displayed-name form lives unchanged in the `From:` header inside the body.

type Sender

type Sender interface {
	Send(ctx context.Context, msg Message) error
}

Sender is the abstract interface every backend implements. Implementations MUST be safe for concurrent use.

type StdoutSender

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

StdoutSender writes a dump of every send to w. Convenient for tests (capture w to assert) and as the dev default when no real backend is configured. Implements Sender.

func NewStdoutSender

func NewStdoutSender(w io.Writer) *StdoutSender

NewStdoutSender returns a sender that writes to w. Pass os.Stdout in dev.

func (*StdoutSender) Send

func (s *StdoutSender) Send(_ context.Context, m Message) error

Send implements Sender.

Jump to

Keyboard shortcuts

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