# Confirmation email not arriving (Supabase, Firebase, WordPress)

> Why sign-up confirmation emails do not arrive, what to check first and how to fix it in Supabase Auth, Firebase Auth and WordPress, with your own SMTP and an authenticated domain.

Source: https://couryo.com/en/guides/confirmation-email-not-arriving · Updated 2026-10-08

Someone signs up, sees "we sent a link to your email" and nothing arrives. They try again, give up, and you lose the sign-up without ever knowing. Most of the time the cause is one of these five, and you can find out which in a few minutes.

## The 5 most common causes

1. **The built-in email service is not meant for production.** Supabase, Firebase and WordPress ship with a default sender designed for testing, with low limits or a generic sender that filters do not know.
2. **The sender domain is not authenticated.** Without aligned SPF, DKIM and DMARC, the email lands in spam or is refused. See [How to set up SPF, DKIM and DMARC](https://couryo.com/en/guides/spf-dkim-dmarc.md).
3. **A sending limit was hit.** The auth system itself has an hourly email limit; testing many times in a row hits it.
4. **The link points to the wrong place.** The configured site URL is `localhost` or another domain, and the link "does not work".
5. **A filter opened the link before the person did.** Some corporate providers visit links to check them. If the link is single-use, it is already spent when the person clicks.

## First: find where the email stopped

| Question | Where to look |
|---|---|
| Did the app ask for the send? | your backend or auth system logs |
| Did the sending server accept it? | the SMTP or API service's dashboard or log (search by recipient) |
| Did the destination server accept it? | the destination's SMTP answer: `250` is accepted; `4xx` is deferred; `5xx` is refused |
| Did it arrive in spam? | ask the person to check spam and Gmail's tabs |

If the email never left the app, it is configuration or a limit. If it left and bounced, the code tells you why: see [SMTP error codes](https://couryo.com/en/guides/smtp-error-codes.md). If it was delivered and the person cannot find it, it is the spam filter.

## Supabase Auth

Supabase's built-in email has a very low hourly limit and, on new projects, only delivers to the project team's addresses. In production, turn on **custom SMTP**:

1. Verify the domain with your sending service and create the SMTP credential.
2. In **Authentication > Emails > SMTP Settings**, turn on **Enable Custom SMTP** and fill in the sender (on the verified domain), host, port, username and password.
3. In **Authentication > Rate Limits**, set the hourly email limit to your volume.
4. In **Authentication > URL Configuration**, check the **Site URL** and **Redirect URLs**.
5. Test and look at **Logs > Auth**: SMTP errors show there, with the code.

The step by step with Couryo's values, including the CLI and the management API, is in [Supabase Auth with custom SMTP](https://couryo.com/en/docs/supabase.md).

## Firebase Auth

By default, Firebase sends from an address on the project's Firebase domain, which is not yours. To send from your domain:

- set up **SMTP** in **Authentication > Templates > SMTP settings**, with a sender on your verified domain; or
- generate the link in your backend with the Admin SDK (`generateEmailVerificationLink`) and send it yourself, with your own HTML.

Both paths, with code, are in [Firebase Auth](https://couryo.com/en/docs/firebase.md).

## WordPress

WordPress sends through the hosting server's `mail()` function, without your domain's authentication. It is the most common cause of "the site's sign-up and password emails never arrive". Install an SMTP plugin (or use the `phpmailer_init` hook), point it at an authenticated service and force the sender to your domain. Step by step in [WordPress and WooCommerce](https://couryo.com/en/docs/wordpress.md).

## When the link arrives "invalid or expired"

If the email arrives but the link no longer works when the person clicks, it is almost always a corporate filter that visited it first. Three ways out:

- **A 6-digit code** instead of a link (Supabase offers `{{ .Token }}` in its templates);
- **an intermediate page with a button** "Confirm email": the filter's visit only opens the page, and confirmation happens on click (a POST);
- links with a reasonable lifetime and a way to request a new one on the same screen.

## The email's text matters too

- **A clear subject with the app's name:** "Confirm your email for Example".
- **A recognizable sender:** "Example <no-reply@example.com>", always on the site's domain.
- **A text part** besides HTML, and the link written out as an alternative to the button.
- **No link shorteners**, no ads and no heavy images.
- One line saying why the person got it and what to do if it was not them.

## Where Couryo fits

Couryo works as the custom SMTP for Supabase, Firebase and WordPress (host `smtp.couryo.com`, username `couryo` and your API key as the password). Each confirmation email shows up in a timeline with the destination server's answer, and when a provider refuses it, the explanation says why in plain words. With a test key, you can test the whole flow without delivering anything. See the [quickstart](https://couryo.com/en/docs/quickstart.md).

## FAQ

### Why does the confirmation email reach me but not my customers?

On Supabase, the built-in sender only delivers to the project team's addresses. In other cases, you always test with the same provider (your Gmail, for example) and the problem shows up at another one (Outlook, a company mailbox). Test with addresses at different providers.

### The confirmation email takes ages to arrive. Is that normal?

No. Confirmation should arrive in seconds. Minutes or hours of delay usually mean the provider is deferring delivery (a `4xx` answer) because of volume or reputation, or a stuck queue in your system. The destination server's answer shows which.

### Can I turn off email confirmation to stop losing sign-ups?

You can, but your list fills with mistyped and fake addresses that bounce and hurt your domain's reputation. Better to make the confirmation arrive.

### Do I need my own domain to send?

For production, yes. Sending from a generic domain (the auth service's or a free mailbox provider's) leaves the message without aligned authentication or brand recognition, and that is where filters are most suspicious.
