# Email provider and DNS

Connect and verify Resend for the Alpha. Other provider instructions are implementation reference only.

HeyCMO is an invitation-only, $0 operational Alpha for Stripe and Resend recovery emails. A person approves every message before it is sent. The guides also describe implementation capabilities outside the Alpha. Their presence here does not make them available in the pilot. [Start with the Alpha checklist](https://docs.heycmo.ai/getting-started/). Help: [alpha@heycmo.ai](mailto:alpha@heycmo.ai).

Setup → **Connect Stripe** and **Email sending**, or Settings → **Connections** → **Stripe and email sending** (the same forms). One paste per provider: HeyCMO checks the key with the provider, stores it encrypted (envelope encryption; AWS KMS once the operator turns it on), creates this workspace's webhook through the provider's API and stores the signing secret the provider returns. You never copy a tenant id or build a webhook by hand.

## Connect your email provider

- **Resend** — Resend → API Keys → create a **Full access** key (HeyCMO also verifies your domain and registers your delivery/bounce webhook with it) → paste → **Connect Resend** (`API`: `POST /v1/connect/resend` with `{"apiKey":"re_…"}`).
- **Postmark** — Postmark → your server → API Tokens → copy the **Server API token** → **Connect Postmark** (`API`: `POST /v1/connect/postmark` with `{"serverToken":"…"}`, and `"broadcastStream"` for a Broadcasts stream). Recovery emails go out on your transactional stream; marketing email needs a Broadcasts stream with Custom unsubscribe handling. Postmark keeps your domain's status on the account, so **Verify domain** ([Verify your sending domain](https://docs.heycmo.ai/email/#verify-your-sending-domain)) asks for an Account API token once and does not store it.
- **Amazon SES** — no key: create an IAM role in your AWS account that HeyCMO may assume with your workspace's external id (the form shows the trust and permissions policies), then give its ARN and your AWS region (`API`: `POST /v1/connect/ses` with `{"roleArn":"arn:aws:iam::…","region":"us-east-1"}`, optionally `"configurationSetName"`). HeyCMO sets up the SNS topic your delivery events arrive through.
- **SendGrid** — SendGrid → Settings → API Keys → create a restricted key with **Mail Send** (and access to the Event Webhook settings, so HeyCMO can set up the signed webhook itself) → **Connect SendGrid** (`API`: `POST /v1/connect/sendgrid` with `{"apiKey":"SG.…"}`, and `"region":"eu"` for an EU account).

You send through one provider at a time. Connecting another one moves every send to it, so the form asks you to confirm the switch (`"switchProvider": true`). Connecting the same provider again is safe: the existing webhooks are reused, not duplicated.

## Verify your sending domain

Setup → **Email sending**, or Settings → **Email** → **Sender identity** → enter your From address (the domain comes from it) and your postal address → Save → add the DNS records your email provider shows you for that domain → back in HeyCMO press **Verify domain** (on Postmark it asks for an Account API token for this one check). Real sends are blocked until the domain is verified (Setup then says **Verified:** and your address) — that's deliberate (fail-closed), not a bug. With SendGrid, connecting already checks the domain against SendGrid's domain authentication.

## Webhooks — usually nothing to do

Connecting Stripe and your email provider created both webhooks: the Stripe one feeds recovered-revenue attribution (`invoice.paid`, `invoice.payment_succeeded`), drafts the first recovery email as soon as a payment fails (`invoice.payment_failed`), the card-expiry email before a renewal (`invoice.upcoming`, and `customer.source.expiring` for a saved card that expires at the end of the month), sees new trials and subscriptions for the conversions you send back to your ad platforms (`customer.subscription.created`), and withdraws a waiting recovery draft when the invoice is paid, the subscription is paused or cancelled, or the invoice is written off (`invoice.marked_uncollectible`, `customer.subscription.paused`, `customer.subscription.updated`, `customer.subscription.deleted`); your email provider's one records delivery events and suppresses bounced and complained recipients. If you connected Stripe before an event was added to this list, HeyCMO adds it to the webhook it created in your Stripe account within a day (connecting again with the same key does it at once). Until Stripe has sent one failed payment, the first email goes with the next daily run, and the loop's run note says so. Setup's **Connect Stripe** and **Email sending** steps turn green only once their webhooks are set up, and Setup → **Advanced / manual setup** shows your workspace id and both endpoint URLs.

Only if a connect answered **"One manual step left"** — a Stripe key without Webhook Endpoints: Write, or a sending-only Resend key — the form shows the exact endpoint URL and events with copy buttons. Add that endpoint in the provider (Stripe → Developers → Webhooks → Add endpoint; Resend → Webhooks), then store the signing secret (`whsec_…`) it gives you in Setup → **Advanced / manual setup** or Settings → **Advanced** → **Integration secrets** → *Stripe webhook signing secret* / *Resend event webhook signing secret* (Postmark and SendGrid have their own fields there for a webhook added by hand). The URL is also on `GET /v1/connect` (`webhookUrl`), and your workspace id is on Settings → **Team & API keys**, with a copy button.

Without the email provider's webhook, dunning still runs but bounces and complaints cannot produce suppression. Without the Stripe one, recoveries are not attributed.
