Declare a named foreign key for every join and table possible-value field
between the ten email tables, plus suppression.source_message_id. Owned
rows cascade, providers/brands/templates with history are RESTRICT, and
optional pointers (template versions, sender address, suppression sources)
are SET NULL so message retention keeps working. The provider delete check
also covers attempts, events and inbox rows. The upgrade script quarantines
orphans before adding the keys; a Testcontainers guardrail test fails when
a new relation has no key.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
For the durable jobs outbox (QRun-IO/qqq#1191, spec section 2.13):
- Each queued message stores one RFC 5322 Message-ID (email_message.rfc_message_id,
unique), derived from the idempotency key (else a stable per-message seed),
and reuses it on every attempt. SMTP, Postmark, SendGrid and Mailgun send it.
SES receives it in the raw MIME but replaces it; this is documented, and
X-QQQ-Email-Id stays on every transport.
- EmailEffects.send(request, effectKey) hands an email to qbit-email's outbox
exactly once per key: QUEUED_OR_DUPLICATE, or REFUSED (suppressed or
invalid; never retried).
- findByIdempotencyKey / findByRfcMessageId look an email up for a reconcile.
- docs/DURABLE-JOBS.md has the outcome mapping and the binding class to add
when QQQ RC.7 ships (EmailJobEffectTarget implements core's EffectTarget;
no SNAPSHOT dependency now).
- Postgres upgrade SQL for existing installs; checkstyle now also covers test
sources (the repo standard), with the existing violations fixed.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
email_provider_sender_address (child of the provider; admin-only;
domain, uniqueness and single-default checks). Sends may name a sender
row (withFromAddressId) or match one by text; rows belong to the
resolved provider, the default row wins, and the provider's from
address stays the fallback. Message rows record from_address_id.
Contingent possible-value filters: fromAddressId by providerId on both
send processes, on Send Test Email (seeded from the acted-on provider)
and on email_message; message ids on attempts and events by provider;
suppression source event by source message. One test per pair.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Phase (c) of docs/DESIGN.md: the email_webhook_inbox and email_event
tables; a /qqq/hooks/email route provider with SES (SNS signature and
certificate host rules, subscription confirmation), Postmark (basic
auth), SendGrid (ECDSA) and Mailgun (HMAC with replay protection)
verification into a durable inbox; a claim-safe inbox processor that
maps provider events to email_event rows, message status and
suppressions; RFC 8058 one-click unsubscribe with a confirmation page;
the Reprocess action; and event-backed home metrics.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Phase (a) part 2 of docs/DESIGN.md: the variable engine with escaping,
if/each and fallbacks; variable schemas; Markdown in the branded
responsive layout with dark-mode colours and contrast checks; HTML and
MJML kinds (MJML through a pluggable compiler at activation); versions
with New Version, Activate Version and Approve For PHI; templated sends
with record variables read as the sender; the classification stand-in
(core #1142); PII/PHI refusal; redacted variable snapshots with
ClassifiedValueTokens-shaped tokens and encrypted PHI bodies (stand-ins
for core #1161); the secure-message built-in; the preview widget; the
home dashboard; contingent possible values; and the canary-PHI egress
test.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Phase (a) part 1 of docs/DESIGN.md: the email_ tables (provider,
message, attempt, template, version, brand, suppression) with Postgres
DDL; provider rows with env-var-name credentials; EmailService with
idempotency keys, suppression and same-transaction enqueue; the
dispatcher with unique-attempt claims, leases, backoff, dead letters,
rate limits and provider health; SMTP (jakarta.mail with auth, TLS and
timeouts) and SES (AWS SDK v2 sesv2 raw) transports; the QBIT_EMAIL
core messaging provider; Resend, Cancel, Send Now and Send Test Email
record actions; scheduled dispatch, maintenance and retention.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>