// how to fix
Mailgun "401 Forbidden": wrong API key or EU/US region mismatch
Mailgun returns 401 Forbidden or Unauthorized. Check the API key type, the "api" username and whether your domain uses the US or EU endpoint.
What it means
Your app called the Mailgun API and got HTTP 401 Unauthorized. The response body is often just the word Forbidden, which is confusing. Mailgun's API reference says 401 means the API key is missing or invalid, while 403 means the key is valid but access to that resource is denied. In practice, a 401 almost always comes from one of the problems below.
Why it happens
- Region mismatch. Each sending domain is created in the US or the EU region. A domain created in the EU must be called on
https://api.eu.mailgun.net/, a US domain onhttps://api.mailgun.net/. Calling the wrong one fails even with a good key. Many libraries and plugins default to the US endpoint. - Wrong kind of key. Mailgun has several keys: the private Mailgun API key (account level), domain sending keys (send only, for one domain), the HTTP webhook signing key and the public verification key. The last two cannot send email.
- A sending key used for another domain or endpoint. A domain sending key only works for
/messagesand/messages.mimeon the domain it was created for. Calling/v3/domainsor another domain with it fails. - Bad Basic Auth. The username must be exactly
apiand the password the key. Some code sends the key as username, or adds spaces or quotes. Older keys start withkey-, and this prefix is part of the key. - Deleted or regenerated key. Keys are shown only once; a teammate may have rotated the key you still have in
.env. - IP allowlist: if API access is restricted to some IP addresses in your account security settings, calls from a new server are refused.
A 404 "Domain not found" usually means the domain name in the URL is wrong or exists in the other region.
How to check
- In the Mailgun panel, open Send, Domains: the list shows each domain's region (US or EU).
- Test your key with
curl, using the endpoint of that region:
curl -s --user 'api:YOUR_API_KEY' \ https://api.eu.mailgun.net/v3/mg.yourdomain.com/messages \ -F from='Test <hello@mg.yourdomain.com>' \ -F to='you@example.com' \ -F subject='Mailgun test' \ -F text='Hello'
If this returns a JSON answer with an id and "Queued", the key and region are right and the problem is in your app's configuration. Try the other endpoint if it fails: if one works and the other does not, it is a region mismatch. Remove .eu for a US domain.
How to fix it
1. Set the region in your library. Examples:
// mailgun.js (Node)
const mg = new Mailgun(FormData).client({
username: 'api',
key: process.env.MAILGUN_API_KEY,
url: 'https://api.eu.mailgun.net', // only for EU domains
});
# Laravel .env
MAILGUN_DOMAIN=mg.yourdomain.com
MAILGUN_SECRET=your-private-or-sending-key
MAILGUN_ENDPOINT=api.eu.mailgun.net
# Symfony Mailer
MAILER_DSN=mailgun+api://KEY:mg.yourdomain.com@default?region=euIn WordPress SMTP plugins, choose the matching Region option. Then:
- Use the right key. Create a new private API key or a domain sending key in the Mailgun panel (API security / sending keys) and store it immediately; you will not see it again. Use the sending key only for sending on its own domain.
- Check for hidden characters: no quotes inside the value, no trailing space or line break from copy and paste.
- Update the IP allowlist if you use one, with the public IP of the server that calls the API.
- For SMTP, the equivalent error is a
535authentication failure. SMTP credentials are per domain and per region: usesmtp.eu.mailgun.orgfor EU domains andsmtp.mailgun.orgfor US ones, with the domain's SMTP login (for examplepostmaster@mg.yourdomain.com). If you use PHPMailer, see PHPMailer "Could not authenticate".
If the call is accepted but the message is refused because you still use the sandbox domain, read Mailgun sandbox: authorized recipients only. If your domain is not verified yet, fix its DNS first with Mailgun domain not verified.
Check that it is fixed
Send a message from your app to the unique address on the Delivmail home page. If it arrives, authentication works; the report then tells you whether SPF, DKIM and DMARC pass for your Mailgun domain. Then resend the messages that failed with 401, and keep the region and key in one configuration place so the next deployment does not bring the error back.
Check that it is fixed
DNS changes can take from a few minutes to a few hours. Then send a new test email or scan your domain again.
Related guides
- Amazon SES SMTP "535 Authentication Credentials Invalid": fix itAmazon SES rejects your SMTP login with 535 Authentication Credentials Invalid. Use real SMTP credentials, the right Region and endpoint, and test them.
- Amazon SES "Throttling: Maximum sending rate exceeded" (454): fix itAmazon SES returns "Maximum sending rate exceeded" or "Daily message quota exceeded". Check your quotas, slow down sending and request an increase.
- Mailgun domain not verified: fix the SPF, DKIM, MX and CNAME recordsMailgun shows your domain as unverified or refuses to send from it. Add the right SPF and DKIM records, avoid common DNS mistakes and verify.
- Mailgun "Sandbox subdomains are for test purposes only" (403): fix itMailgun refuses to send from your sandbox domain to an address that is not an authorized recipient. Authorize test addresses or add your own domain.
- Mailgun 605 "Not delivering to previously bounced address": fixMailgun refuses to send with code 605 because the address bounced before. Learn when to remove it from the bounce list and when to leave it there.