Auth0's built-in email sender is only for testing, so every production tenant needs its own provider. To send through OwnMailServer, open Branding, then Email Provider, turn on Use my own email provider, choose SMTP, and enter smtp.ownmailserver.com, port 587, any username and an API key as the password, with a From address on your verified domain. Then click Send Test Email. It takes about ten minutes.
| Approach | Good for | Code |
|---|---|---|
| SMTP | Most tenants: Auth0's templates, sent from your domain | None |
| Custom Provider Action + our API | Your own logic per message type, retries, logging | One Action |
Why Auth0 needs its own email provider
Auth0 sends email for verification, password resets, verification codes, MFA codes, welcome messages, blocked-account notices and organization invitations. Out of the box it uses a built-in sender that, as of October 2026, Auth0 documents like this:
- All emails come from
no-reply@auth0user.net. You can't change the From address. - It allows 10 emails a minute, of every type together.
- You can't use custom email templates.
Auth0 says to use it for testing only. With your own provider, sign-in emails come from your domain, signed with your DKIM key, and every bounce and complaint shows up in your dashboard.
What you need before you start
- An approved OwnMailServer account with a verified sending domain. The From address must be on that domain, or we refuse the email with
550. The API docs list the DNS records, and the DKIM guide explains them. - An API key, created in your dashboard under API keys & SMTP. Choose Sending only (the default), limited to your sending domain, so the key Auth0 stores can't do anything but send. Make one just for Auth0, so you can revoke it without touching your other apps.
- Ideally a separate subdomain for auth email, such as
no-reply@auth.acme.com. Mailbox providers judge each domain's reputation, so a newsletter that draws complaints won't pull your password resets into spam.
Step 1: Enter the SMTP settings
In the Auth0 Dashboard, open Branding, then Email Provider. Turn on Use my own email provider, select SMTP, and fill in:
| Field | Value |
|---|---|
| From | no-reply@auth.acme.com (on your verified domain) |
| Host | smtp.ownmailserver.com |
| Port | 587 |
| Username | ownmailserver (we accept any value) |
| Password | Your API key |
Click Save. Auth0 lists four requirements for an SMTP server, and we meet each one:
| Auth0 requires | OwnMailServer |
|---|---|
| SMTP AUTH with the LOGIN method | LOGIN and PLAIN, after STARTTLS |
| TLS 1.2 or later | Yes, on port 587 |
| A certificate from a public certificate authority | Let's Encrypt, valid for smtp.ownmailserver.com |
| Accept connections from Auth0's IP addresses | We accept connections from anywhere and check the API key |
If you change the host, port or username later, Auth0 asks for the password again, so keep the API key somewhere safe, such as your secrets manager.
To set the same thing from a script or CI, use Auth0's Management API with a token that has the update:email_provider scope. Use POST the first time and PATCH to change it:
curl -X PATCH "https://$AUTH0_DOMAIN/api/v2/emails/provider" \
-H "Authorization: Bearer $AUTH0_MGMT_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "smtp",
"enabled": true,
"default_from_address": "no-reply@auth.acme.com",
"credentials": {
"smtp_host": "smtp.ownmailserver.com",
"smtp_port": 587,
"smtp_user": "ownmailserver",
"smtp_pass": "'"$OMS_API_KEY"'"
}
}'
Step 2: Send a test email
Click Send Test Email on the same page. Then search for the address in your OwnMailServer dashboard to see the delivery, or ask the Claude connector what happened to it. If nothing arrives after a few minutes, check Monitoring, then Logs in Auth0 for a failed send:
| You see | Cause | Fix |
|---|---|---|
535 / authentication failed |
Password isn't a valid API key | Paste the full key, or create a new one |
550 |
From domain isn't verified, or the account is pending | Finish domain setup in the dashboard |
450 |
Warm-up cap or 10 a second reached | Wait; Auth0 logs the failure |
421 too many failed logins |
5 failed logins from one IP address | Fix the password, wait 15 minutes |
Email still from auth0user.net |
The provider toggle is off or not saved | Turn on Use my own email provider and save |
Step 3: Edit the templates
With your own provider set up, open Branding, then Email Templates to change each email: verification email (link and code), change password, welcome email, MFA enrollment, blocked account and others. Each template has its own From field, which overrides the default, so keep it on your verified domain too. Templates use Liquid, with variables such as {{ url }}, {{ user.email }} and {{ application.name }}.
Keep auth emails plain: a short line, one button, the same link as text, and no tracking or marketing. That's what mailbox providers expect from a password reset, and it's what gets it to the inbox quickly.
Option B: A Custom Provider Action that calls our API
If you want your own logic, such as logging each send or handling message types differently, choose Custom Provider under Branding, then Email Provider. Auth0 then stops using SMTP and runs an Action on the custom-email-provider trigger for every email, passing the rendered subject, HTML and text. Your Action sends them through POST /emails.
Enter the From address, add your API key as a secret named OMS_API_KEY (the key icon in the editor), and use this code:
exports.onExecuteCustomEmailProvider = async (event, api) => {
const n = event.notification;
let res;
try {
res = await fetch("https://api.ownmailserver.com/emails", {
method: "POST",
headers: {
Authorization: `Bearer ${event.secrets.OMS_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
from: n.from,
to: n.to,
subject: n.subject,
html: n.html,
text: n.text,
tags: [{ name: "auth0", value: n.message_type }],
}),
});
} catch (err) {
api.notification.retry(`Network error: ${err.message}`);
return;
}
if (res.ok) return;
const body = (await res.text()).slice(0, 500);
// 429 (rate or daily cap) and 5xx are temporary: Auth0 retries up to 5 times.
if (res.status === 429 || res.status >= 500) api.notification.retry(`OwnMailServer ${res.status}: ${body}`);
else api.notification.drop(`OwnMailServer ${res.status}: ${body}`);
};
Save to deploy it, then click Send Test Email. Errors such as an unverified domain (4xx other than 429) won't fix themselves, so the Action drops them and Auth0 logs the reason instead of retrying. The tags value records Auth0's message type with each email, such as reset_email or verify_email, so you can tell them apart later.
An Action is a tenant-wide setting: only one Action can be bound to the custom-email-provider trigger. If you manage Auth0 with Terraform, the auth0_email_provider resource with name = "custom" does the same thing.
Keep auth email within your warm-up cap
A new OwnMailServer account starts at a few hundred recipients a day and rises about 25% after each clean day (how warm-up works). Your dashboard shows today's cap. Verification and reset emails rarely come close. If you're moving an existing tenant with many daily signups, keep the old provider meanwhile and switch Auth0 over once the cap covers a normal day, as described in our migration guide.
The same setup works for other auth platforms. See Supabase custom SMTP and Firebase email.
Want help moving your auth email? See pricing, or write to hello@ownmailserver.com.