cratefield-adapter-resend
[Mailer] port over the Resend REST API for the
Cratefield harness. Uses the runtime's HttpClient port — no reqwest,
no vendor SDK — so it runs unchanged on Workers (worker::Fetch) and
natively.
It also carries the inbound direction: ResendInbound verifies Resend's
email.received webhook with the Svix scheme and parses it into an
InboundMessage, ready to hand to a module. The webhook is metadata only
— the message body is a separate Received-emails API call the caller
makes, not this crate. Configure the signing secret with
ResendInbound::new(secret) or RESEND_WEBHOOK_SECRET via
ResendInbound::from_env().
Usage
use Arc;
use Resend;
use ;
// With a key:
let mailer = new;
// Without a key (degraded mode): send() -> Ok(SendOutcome::NotConfigured),
// no network call. Wire it into the runtime:
let runtime = new.db.mailer;
Resend::from_env(http, clock) reads RESEND_API_KEY, MAIL_FROM,
MAIL_REPLY_TO from the process environment (native/self-hosted). On
Workers, read the secrets from the venture's Env and call Resend::new.
The Clock is what lets the adapter read the HTTP-date form of
Retry-After (issue #278); without it a date-form 429 would read as
"retry now".
Error mapping (to cratefield_core::MailError): 401/403 →
Unauthorized/DomainNotVerified { domain } (domain parsed from Resend's
message), 422 → Invalid { detail }, 429 → RateLimited { retry_after }
(from the Retry-After header), 5xx → Upstream. No error Display ever
includes the API key. text is always sent alongside html; the
Idempotency-Key header is set from Message::idempotency_key.
Verify a sending subdomain (not the apex)
The Resend account has no verified domain yet; until it does, real
sends 403 with "Domain ... is not verified" and this adapter maps that to
MailError::DomainNotVerified. Until then, forms run in the degraded
NotConfigured/503 mode.
When verifying:
- In the Resend dashboard add a subdomain, e.g.
send.example.com, not the apex. - Add the DKIM/SPF records Resend shows to the subdomain's DNS zone.
- Wait for "Verified", then set
MAIL_FROMto an address on that subdomain (e.g.Acme <no-reply@send.example.com>).
Why not the apex? The apex domain (e.g. example.com) carries the
inbound Email Routing MX records. Adding Resend's outbound DKIM/SPF to the
apex would mix inbound routing and outbound sending policy on the same
name and can break delivered mail and future provider moves. A dedicated
send. subdomain keeps them isolated, and lets inbound routing stay
untouched if the outbound provider ever changes.
Probing the key
Until a domain is verified, the key is send-only. Probe it with a real
send (expect 403 DomainNotVerified, which proves the key itself is
valid):
A 401 means the key is bad; 403 with the domain message means the key works but the domain is unverified.
MIT. Built in the open for Cratefield, a Factory Zero venture.