# Signup welcome email

Each successful new signup queues one welcome email from `welcome@clawdmail.app` with fresh artwork generated through the server's `XAI_API_KEY` using **grok-imagine-image-2.0**. The public [CLAWD welcome illustration](../public/brand/clawd-mail-welcome.jpg) and [its provenance](../public/brand/clawd-mail-welcome.json) document the generated brand reference; each delivered illustration has its own private provenance.

The worker generates a fresh illustration for each new signup and embeds it as a CID inline attachment. It caches the image and provenance in private R2 storage before sending, so delivery retries reuse the same art. Signup finishes while the continuous worker prepares and sends the queued email. The public illustration is the generated reference and preview artwork. No signup names, email addresses or private mail are sent to xAI. Existing accounts are not backfilled. Public signups are approved automatically; the welcome points users to sign in and complete the required first-login X welcome verification before creating an inbox. Both HTML and plain text are included.

## Production configuration

Set these private backend variables on **both** the Railway web service and continuous mail worker:

```env
RESEND_API_KEY=YOUR_RESEND_API_KEY
WEBHOOK_SECRET_RESEND=YOUR_WEBHOOK_SIGNING_SECRET
WEBHOOK_URL_RESEND=https://clawdmail.app/hook/resend
MAIL_WELCOME_ENABLED=true
MAIL_WELCOME_FROM=welcome@clawdmail.app
```

`CLOUDFLARE_API_TOKEN` continues to manage routing/domain configuration. Resend sends primary-domain mail when its key is configured; retained legacy inbox domains continue through their existing Cloudflare sender. Without Resend, `CLOUDFLARE_EMAIL_SENDING_TOKEN` sends through Cloudflare. Local credentials live in ignored backend environment files with mode `0600`; never use a `VUE_APP_*` variable.

This app runs on Railway/Node and uses the official Resend Node.js SDK. The adapter preserves the inline artwork with `contentId` matching the HTML CID. The app's existing Cloudflare Email Worker handles incoming mail independently. The Cloudflare sender uses its account Email Sending REST endpoint.

## Delivery behavior

Signup inserts a unique `clawd_mail_welcome_jobs` row in its membership transaction. The worker claims jobs with a lease and checks them every five seconds. Each job has a four-minute lease covering bounded xAI generation and sending. Preparation failures and explicit rate limits retry up to three attempts. The Resend adapter retries transient transport, rate-limit, and server failures with the same idempotency key and payload. Unconfirmed acceptance after bounded retries, interrupted sends, and Cloudflare transport/5xx outcomes remain ambiguous and are never blindly resent. Permanently bounced recipients stop as failed.

The account's `/api/account/welcome` endpoint returns only its own status. The signup waiting page and account page distinguish preparation, provider acceptance, delivery, failure and uncertainty. Placeholder/reserved test domains are skipped instead of sending to nonexistent addresses. Blocked accounts are skipped if blocked before dispatch.

To regenerate the shared artwork intentionally:

```sh
node scripts/generate-welcome-art.cjs
```

The local [email preview](../artifacts/qa/welcome/email-preview.html) shows the HTML and embedded art. Generation uses the server xAI key and the pinned model; there is no fallback model.

Official references: [Resend Node.js sending](https://resend.com/docs/send-with-nodejs), [Resend signed webhooks](https://resend.com/docs/webhooks/verify-webhooks-requests), [Cloudflare REST sending](https://developers.cloudflare.com/email-service/api/send-emails/rest-api/), [native Worker binding](https://developers.cloudflare.com/email-service/api/send-emails/workers-api/), [Cloudflare Email Service skill](/Users/8bit/.agents/skills/cloudflare-email-service/SKILL.md).
