Sending emails
With sendEmails: true, your Convex backend sends the auth emails through Resend, using the Convex Resend component. You need it for one-time codes, magic links and organization invitations, and it makes password users verify their address.
Turn it on
Set the flag:
Create an API key in Resend under API Keys, add your sending domain under Domains and follow its DNS instructions. Then set both variables in Convex:
Both are required. Without EMAIL_SEND_FROM, every send throws EMAIL_SEND_FROM environment variable is required but not set, and the sign-up, reset or invitation that triggered it fails. Use an address on the domain you verified in Resend.
The component runs with testMode: false, so every address gets real mail, including the ones your tests sign up with.
Emails the Auth UI sends
| Subject | Sent when | |
|---|---|---|
| Verification | Verify your email address | Someone signs up with a password. Also sent to the new address when a user with an unverified email changes it. |
| Sign-in code | <code> is your verification code | Someone signs in with emailOTP. |
| Magic link | Sign in to <brandName> | Someone signs in with magicLink. |
| Password reset | Reset your password | Someone clicks “Forgot password?” on the password step. |
| Email change | Confirm your email address change | A user with a verified email changes it in the user profile. It goes to the current address. |
| Invitation | Join <organization> on <brandName> | An owner or admin invites someone to an organization. |
The email change is always on, so it sends mail even when sendEmails is off. Set EMAIL_SEND_FROM and RESEND_API_KEY before users can reach the user profile, or the change fails.
Verification for password sign-in
With sendEmails: true, a password account can’t sign in until its address is verified. After sign-up, the form shows “Check your email”, and the link in the email signs the user in. A user who tries to sign in before that sees “Please verify your email address.” The Auth UI doesn’t send a new link at that point.
The password step only offers “Forgot password?” when sendEmails is on.
Track delivery with the Resend webhook
This step is optional. It lets the Resend component record what happened to each email (delivered, bounced and so on).
The route is already there: src/convex/http.ts, which the base registry item installs, registers POST /resend-webhook and hands it to the component. In Resend, under Webhooks, add an endpoint pointing at your deployment’s HTTP actions URL:
Select the email.* events. Copy the signing secret and set it in Convex:
Each Convex deployment has its own .convex.site URL, so production and development each need their own webhook and secret.
Brand your emails
Emails use brandName and brandTagline from src/convex/auth.constants.ts, the same values the sign-in form shows. The name heads every email and appears in the magic-link and invitation subjects. The footer reads Acme — Secure authentication for your application.
To show your logo beside the name, set a public image URL in Convex:
Use a square PNG of at least 56×56 px; emails show it at 28×28 px. Gmail and Outlook don’t display SVG. Set BRAND_LOGO_URL on every deployment that sends email.
Earlier versions read the brand from the BRAND_NAME and BRAND_TAGLINE environment variables. Move their values into AUTH_CONSTANTS and remove the variables.
Customize the templates
The emails are HTML strings in src/convex/model/emails/templates/, installed by the email/convex registry item, so you edit them like any other file in your project.
| File | What it holds |
|---|---|
baseEmail.ts | The layout every email shares (brand header, card, footer), its colors, and the helpers heading, paragraph, button, linkFallback and note. |
emailTemplates.ts | The wording of each email in the table above. |
src/convex/email.ts | The subject lines, and which template each email uses. |
Match your theme
Email clients don’t load your app’s CSS, so your theme can’t reach the emails. Their colors are hex values at the top of baseEmail.ts. To give the button your brand color, change action for its fill and onAction for its label:
Keep a contrast of at least 4.5:1 between action and onAction, and between muted and both page and surface, so small text stays readable.
Keep user input escaped
Names, email addresses and organization names come from your users. heading, button and note escape their text. paragraph takes HTML, so pass any user value through escapeHtml before you put it into a paragraph:
Troubleshooting
- Nothing arrives. Open the Convex logs for the deployment. A missing
EMAIL_SEND_FROMorRESEND_API_KEYshows up there. Then check the Resend dashboard and your spam folder. - Resend rejects the sender. The domain in
EMAIL_SEND_FROMisn’t verified in Resend. - Webhook signature errors.
RESEND_WEBHOOK_SECRETdoesn’t match the signing secret of that deployment’s webhook.
Related
- Configure features:
sendEmailsand the features that need it. - Validate emails: check addresses before sign-up.
- Organizations: invitations.