An email API key is the secret credential that lets your application authenticate with an email provider and send messages through its API. Creating one is easy; using it safely requires separating environments, verifying your sending domain, keeping the key out of browser code and Git history, and confirming that a successful API response becomes a delivered email.
What an email API key is—and what it is not
An email API key is a provider-issued secret token. Your application includes it with an API request so the provider can identify the account, apply the key’s permissions, and decide whether to accept the operation.
It is not the same thing as:
- Your email inbox password. An API key authenticates software to an email platform, not a human to Gmail, Outlook, or another mailbox.
- A DNS record. SPF, DKIM, and DMARC records authorize and authenticate the domain that appears in email. The API key authorizes your app to ask a provider to send.
- An SMTP password. Some providers support SMTP credentials as an alternative to an HTTP API. An API key may be used as an SMTP credential in some vendor-specific setups, but the request format and endpoint differ.
- A public website token. An email sending key is a secret. Treat it as a credential that can spend your sending allowance, expose email activity, or be used to send unwanted mail if stolen.
In practical terms, an email API key sits between your backend and your delivery provider:
Your server or serverless function
↓ authenticated HTTPS request
Email provider API
↓
Recipient mail server and inbox
For example, Resend authenticates API calls with an Authorization: Bearer ... header. Postmark uses an X-Postmark-Server-Token header for server-level email sending. Those details are provider-specific; never copy an authentication header from one email API into another. (resend.com)
Why you need an email API key
Your app needs an email API key whenever it sends email as part of a workflow rather than through a person’s mail client. Common examples include:
- account verification and password-reset emails;
- receipts, invoices, shipping notices, and alerts;
- invite emails for SaaS products;
- contact-form notifications;
- product lifecycle messages, such as trial reminders;
- inbound-email processing or webhooks, where supported by the provider.
An API is especially useful when email needs to be sent from application logic. Your code can pass recipient data, a subject, HTML, plain text, tags, template variables, attachments, and provider-specific options in a structured request. The provider returns an identifier or status that your system can store alongside the user action that triggered the message.
The key point: a key authorizes the request, not the message’s deliverability. A valid key can still produce a rejected or undelivered message if the sender domain is unverified, the From address is not permitted, the payload is invalid, the recipient is suppressed, or the provider blocks the request for an account or policy reason.
Before creating an email API key: set up the sending identity
Do not begin by pasting a key into code. First decide which domain and which type of mail the application will send.
Use a domain you control
For production sending, use a domain or subdomain that your team controls in DNS, such as:
example.com
mail.example.com
notify.example.com
A dedicated sending subdomain can make operational separation clearer. For instance, you might send transactional messages from notify.example.com while marketing mail uses news.example.com. This does not automatically guarantee inbox placement, but it gives you clearer DNS and reputation boundaries.
Email providers generally require domain verification before production sending. Resend, for example, provides DNS records for domain ownership and sending authorization, including DKIM and SPF-related records; the values must match the provider-generated values exactly. Mailgun likewise describes domain verification as confirmation of domain ownership and sending authorization. (resend.com)
Understand the DNS records you will encounter
Your provider—not a generic blog post—should supply the precise hostnames and values to publish. Values differ by provider, account, region, and domain configuration. Still, the record shapes are useful to recognize:
Type: TXT
Host/Name: resend._domainkey.notify
Value: p=provider-generated-DKIM-public-key
Type: TXT
Host/Name: notify
Value: v=spf1 include:provider-example.net ~all
Type: TXT
Host/Name: _dmarc
Value: v=DMARC1; p=none; rua=mailto:dmarc@example.com
The sample values above are illustrative only. Do not publish them verbatim. Copy the exact records shown in your provider dashboard.
DKIM enables a receiving server to look up a public key in DNS and verify a message signature. SPF identifies authorized sending infrastructure for a domain or subdomain. DMARC tells receiving servers how to handle mail that fails aligned authentication checks and can send reports to the address you specify. Resend’s documentation explains that DMARC is published as a TXT record at _dmarc and evaluates SPF and DKIM authentication. (resend.com)
Avoid common DNS setup mistakes
The most frequent failure is not “DNS takes time”; it is publishing a nearly correct record in the wrong place. Check these items before retrying verification:
- Use the hostname exactly as shown. Some DNS dashboards append your root domain automatically. If the provider says
resend._domainkey.example.com, the DNS UI may expect onlyresend._domainkey. - Do not alter long DKIM values. Copy them exactly. Some DNS systems wrap long values visually; that is different from adding spaces or truncating text.
- Add records to the sending subdomain when the provider specifies one. A record for
example.comdoes not always verifynotify.example.com. - Do not create multiple conflicting SPF TXT records for the same host. Consolidate mechanisms into one valid SPF policy if your existing mail setup already uses SPF.
- Wait for the provider’s verification status, not just a DNS editor’s save confirmation. The provider must be able to resolve the record publicly.
Resend specifically calls out missing required records, records added to the root instead of the sending subdomain, mismatched values, and DNS hosts that append domain names to MX targets as common verification issues. (resend.com)
How to create an email API key safely
The names in your provider’s UI will vary, but the workflow is consistent.
1. Create separate keys for separate environments
Create at least one key for each environment that can send mail:
email-prod-transactional
email-staging-test
email-local-development
Do not reuse one all-powerful key across local development, preview deployments, staging, background workers, and production. Separate keys let you revoke one environment without breaking every other sender. They also make activity logs more useful during incident response.
Resend notes that multiple keys can isolate application actions, provide per-key logs, help detect abuse, and limit damage from accidental or malicious use. (resend.com)
2. Apply least privilege
Choose the narrowest available permission. A service that only sends transactional mail should not receive permission to create domains, change webhooks, manage audiences, or create more API keys.
For example, Resend offers a sending-only permission and a broader full-access option; its documentation recommends sending-only access unless the key genuinely needs to manage other API resources. It also supports limiting a sending-access key to a specific domain. (resend.com)
A practical permission design looks like this:
| Workload | Recommended key scope |
|---|---|
| Production application sending receipts | Send-only, limited to the transactional sending domain if supported |
| CI integration test that validates payloads | Test or sandbox token, no production sending rights |
| Internal provisioning service | Separate management key, stored in a restricted secrets manager |
| Marketing platform integration | Its own key and sender domain or stream where the provider supports it |
3. Label the key for a real operational purpose
A label such as Production is better than nothing, but prod-checkout-receipts-us-east is better because a teammate can immediately identify its owner and purpose.
Good key labels answer three questions:
- Which environment uses it?
- Which service owns it?
- What is it allowed to do?
4. Copy the secret once and store it immediately
Many providers show a newly created key only once. Resend explicitly documents one-time key visibility as a security measure. If you close the dialog before storing it, create a replacement key rather than searching screenshots, chat logs, or browser history. (resend.com)
Where to store an email API key
Store an email API key in a secret-management mechanism appropriate to the environment. The right implementation differs between local development, a hosted app, and infrastructure automation, but the rule does not: the secret must stay outside source code and outside client-side bundles.
OWASP recommends centralized storage, provisioning, auditing, rotation, and management of secrets rather than scattering plaintext credentials through source and configuration. (cheatsheetseries.owasp.org)
Local development: use an ignored environment file
For a Node.js app, a local .env file is a common choice:
EMAIL_API_KEY=re_replace_with_your_real_secret
EMAIL_FROM=Acme Alerts <alerts@notify.example.com>
Then ensure the file is not committed:
.env
.env.local
.env.production
Your application should read the secret from its runtime environment rather than writing it into source code:
const emailApiKey = process.env.EMAIL_API_KEY;
if (!emailApiKey) {
throw new Error('EMAIL_API_KEY is not configured');
}
Resend’s setup guidance similarly demonstrates storing a key in an environment variable and adding .env to .gitignore when a local secret file is used. (resend.com)
Hosted applications: use the platform’s encrypted secret settings
For a deployed application, set EMAIL_API_KEY in the hosting platform’s environment-variable or secret settings. That could be your serverless host, container platform, CI/CD system, or cloud secret manager.
Avoid putting the value in:
- frontend build variables such as
NEXT_PUBLIC_*,VITE_*, or other browser-exposed prefixes; - a client-side React component;
- mobile app source code;
- Dockerfiles, image layers, or static configuration committed to a repository;
- support tickets, analytics events, logs, or error messages.
A browser user can inspect network requests and downloaded JavaScript. If the key is there, it is no longer a secret. Make the email API request from your server, serverless route, trusted backend worker, or another controlled runtime.
Teams and production systems: use a secrets manager where possible
A secrets manager provides centralized access control and can make rotation, auditing, and deployment safer. OWASP’s application security guidance specifically calls for a proper secrets vault, separate keys when multiple keys are needed, access logging, and key-rotation support. (top10proactive.owasp.org)
The implementation may be AWS Secrets Manager, Google Secret Manager, Azure Key Vault, HashiCorp Vault, a platform-native encrypted secret store, or a comparable managed system. The product choice matters less than the operating model: limit who and what can read the secret, inject it only at runtime, and avoid exposing it in logs.
How to use an email API key in a real request
The following worked example uses Resend because its API uses a clear Bearer-token pattern. The provider choice is not universal: endpoint paths, headers, payload field names, sender rules, rate limits, and response formats vary by vendor.
Worked example: send a transactional email from a Node.js server
Prerequisites:
- You have created a sending-only API key.
notify.example.comor your chosen domain is verified with the provider.- The environment running this code has
EMAIL_API_KEYconfigured. - The code runs on a server, serverless function, or backend worker—not in a browser.
Create send-welcome.js:
const recipient = 'you@example.net';
const apiKey = process.env.EMAIL_API_KEY;
if (!apiKey) {
throw new Error('Missing EMAIL_API_KEY');
}
const response = await fetch('https://api.resend.com/emails', {
method: 'POST',
headers: {
Authorization: `Bearer ${apiKey}`,
'Content-Type': 'application/json',
'User-Agent': 'acme-welcome-service/1.0'
},
body: JSON.stringify({
from: 'Acme Alerts <alerts@notify.example.com>',
to: [recipient],
subject: 'Welcome to Acme',
html: '<h1>Welcome</h1><p>Your account is ready.</p>',
text: 'Welcome. Your account is ready.'
})
});
const result = await response.json();
if (!response.ok) {
console.error('Email API request failed', {
status: response.status,
result
});
process.exit(1);
}
console.log('Email accepted by provider:', result);
Run it with the environment variable available to the process:
EMAIL_API_KEY='re_your_real_key_here' node send-welcome.js
Resend’s send endpoint accepts from, to, subject, and HTML content, and returns a message identifier when the request is accepted. Its API documentation also says requests must use HTTPS and include an Authorization Bearer token; its API introduction states that a User-Agent header is required. (resend.com)
The same request with cURL
Use cURL only from a trusted terminal. Do not paste a real production key into a recorded screen share, shared shell history, support ticket, or public gist.
curl -X POST 'https://api.resend.com/emails' \
-H "Authorization: Bearer $EMAIL_API_KEY" \
-H 'Content-Type: application/json' \
-H 'User-Agent: acme-welcome-service/1.0' \
-d '{
"from": "Acme Alerts <alerts@notify.example.com>",
"to": ["you@example.net"],
"subject": "Welcome to Acme",
"html": "<h1>Welcome</h1><p>Your account is ready.</p>",
"text": "Welcome. Your account is ready."
}'
A minimal API request should include both HTML and plain-text content where the provider supports it. The plain-text version gives receiving systems and recipients a readable fallback if HTML cannot be rendered.
For an implementation-specific endpoint, SDK, and setup detail, consult your provider’s email API setup reference rather than assuming another vendor’s example will work unchanged.
How to know the email API key worked
A working key is more than “the code did not throw an error.” Validate the entire path in stages.
Stage 1: authentication succeeded
The provider should return a successful HTTP response for a valid request. If you receive 401 Unauthorized, check for a missing header, incorrect header name, malformed token, revoked key, or a secret that was not injected into the runtime.
Postmark documents 401 responses for missing or incorrect API token headers. Resend documents a missing API key as a 401 condition and an invalid key as a 403 condition. Exact statuses and error bodies differ by provider, so use the response body and provider documentation rather than relying on a single universal error map. (postmarkapp.com)
Stage 2: the provider accepted the message
Log the provider’s message ID, request ID, and non-sensitive response data. Associate the message ID with your application’s event—for example, an order ID or user ID—so support staff can trace a customer report without searching arbitrary logs.
Do not log the API key, the full Authorization header, or entire recipient payloads if that would expose sensitive user data.
Stage 3: the message reached the recipient mailbox
An accepted API request is not proof of inbox delivery. Check the provider’s event or message activity view for states such as accepted, delivered, bounced, deferred, complained, or suppressed. Then verify the recipient inbox and spam folder with a mailbox you control.
For a production-ready test, send to at least two mailbox providers you control, such as one Gmail account and one Outlook account. This does not measure all recipient environments, but it catches obvious sender-domain, content, and routing issues.
Stage 4: authentication passed
Open the received message’s technical details or “show original” view and inspect authentication results. Look for passing DKIM and SPF results, and confirm DMARC alignment where you have configured DMARC.
This step matters because a message can appear in your own test inbox while still having an authentication configuration that will create problems at scale or with stricter recipients.
Email API key errors and how to fix them
“Missing API key” or “Unauthorized”
Likely causes: the environment variable is absent, the header name is wrong, the value has an extra quote or whitespace, or the key was deleted.
Fix: print only whether the variable exists—not its value—then verify the provider’s required header syntax. Restart local dev servers after changing environment files, because many frameworks load them only at startup.
console.log('EMAIL_API_KEY configured:', Boolean(process.env.EMAIL_API_KEY));
“Invalid API key” or “Forbidden”
Likely causes: a copied key is incomplete, a secret was rotated, the application is reading an old deployment variable, or the request uses a test key against the wrong account or endpoint.
Fix: create a replacement key with the same intended scope, update the runtime secret, deploy it everywhere that uses the old key, verify logs for the new key, then revoke the old key. During a controlled rotation, keep the old and new keys active briefly so deployment ordering does not interrupt sending. Resend describes this create-update-deploy-verify-delete sequence and warns against deleting the old key before the replacement is active. (resend.com)
“This key does not have permission”
Likely causes: a send-only key is trying to call an administrative endpoint, or a domain-restricted key is attempting to send from another domain.
Fix: use a separate management key for provisioning tasks, or change the service to use the correct narrowly scoped key. Do not solve this by upgrading every production workload to full account access.
“Sender domain is not verified”
Likely causes: the From address uses a domain that is not verified, DNS records are incomplete, the DNS record host is wrong, or you are sending from a domain outside the key’s allowed scope.
Fix: compare every record in the provider dashboard to your authoritative DNS zone, character by character. Then rerun provider verification. Resend’s error guidance states that production delivery to other recipients requires a verified domain and a From address using that domain. (resend.com)
“The request succeeded, but no email arrived”
Likely causes: the recipient address is wrong, a message bounced, the recipient is on a suppression list, the message was filtered into spam, or the provider accepted the message but downstream delivery has not completed.
Fix: inspect the provider’s message event log using the returned message ID. Check the recipient’s spam folder and message headers. Do not blindly retry a successful send request: that can create duplicate receipts, password reset messages, or order notifications.
Where an API supports idempotency keys, use an application-generated unique value for retry-prone operations. For example, an order receipt could use an ID derived from order-12345-receipt-v1, ensuring a network retry does not silently create multiple sends.
Security practices for email API keys
An email API key should be treated like a production password with programmatic privileges. The following baseline is appropriate for most teams.
Keep the key server-side
Never ship a mail-sending key in a browser bundle. A secure architecture looks like this:
Browser form → your authenticated backend endpoint → email provider API
The browser can ask your backend to perform an allowed action, such as sending a password-reset request. The backend validates the user and request, decides whether email should be sent, and uses the secret internally.
Do not build this architecture instead:
Browser form → email provider API using a secret key
Resend explicitly advises against exposing API keys in browsers or other client-side code. (resend.com)
Give every system its own key
Use unique keys for production, staging, CI, worker queues, and third-party integrations. This makes revocation surgical. If a staging key leaks, you can disable it without stopping order receipts from production.
Rotate keys deliberately
Rotation means replacing a working credential without causing downtime:
- Create a new key with the same minimum permissions and domain restriction.
- Put the new key into the secret store.
- Deploy every service that uses the old key.
- Confirm recent successful requests are attributed to the new key.
- Revoke the old key.
- Record the key owner, purpose, and rotation date.
A fixed schedule can be useful, but immediate rotation is mandatory when a secret may have been exposed. Some providers do not automatically expire API keys, so do not assume a forgotten key becomes harmless on its own. Resend states that its keys remain valid until manually deleted and recommends regular rotation. (resend.com)
Prevent Git leaks before they happen
Add local secret files to .gitignore, use code-review checks, and enable secret scanning or pre-commit detection. GitHub’s push protection is designed to block pushes containing detected credentials before they reach a repository, while secret scanning can scan Git history for hardcoded credentials. (docs.github.com)
If you commit a real email API key, assume it is compromised even if you delete the file in the next commit. Revoke the key first, replace it in your application, inspect provider logs for suspicious activity, and then clean the repository history if needed. GitHub’s remediation guidance emphasizes that simply removing a leaked secret in a later commit does not prevent exploitation. (docs.github.com)
Choosing between an API key, SMTP credentials, and OAuth
The right authentication method depends on what you are connecting to.
Email API key
Best for application-triggered transactional email through a provider’s HTTPS API. You get structured JSON requests, provider response IDs, typed SDKs where available, and access to email-specific features such as templates, tags, webhooks, suppressions, and scheduled sends when supported.
SMTP credentials
Best when an existing application, CMS, or legacy framework already understands SMTP but cannot easily call a modern HTTP API. SMTP can be a sound choice, but it may provide less structured application feedback than an API integration. Provider-specific SMTP hosts, ports, usernames, and TLS requirements vary.
OAuth
Best when an application must act on behalf of a user’s mailbox account, such as reading or sending through that user’s Microsoft 365 or Google Workspace mailbox with delegated authorization. OAuth access tokens are not interchangeable with a transactional email provider’s API key.
For most SaaS product email—password resets, receipts, invitations, alerts—the API-key approach is the cleanest because the message is sent by your product’s authenticated domain rather than by an individual employee mailbox.
Operational checklist for production email sending
Before enabling a new production feature, confirm all of the following:
- A verified sending domain or subdomain is configured.
- SPF and DKIM records match the provider-provided values.
- DMARC is published and monitored for your domain strategy.
- A dedicated production email API key exists.
- The key has send-only permissions where possible.
- The key is restricted to the intended sending domain where possible.
- The key is stored in a secret manager or protected deployment-secret setting.
- The key is not present in frontend code, Git history, logs, screenshots, or documentation examples.
- The application includes a plain-text message version alongside HTML where appropriate.
- The application records the provider message ID for support and debugging.
- Bounce, complaint, suppression, and delivery events are monitored.
- Retry logic cannot create duplicate transactional messages.
- A rotation owner and incident-response process are documented.
This is also the point to understand your provider’s message volume, feature, and retention limits; compare transactional email pricing against the way your application actually sends rather than selecting a plan based solely on a headline monthly email count.
Conclusion
An email API key is small, but it is a high-impact production credential. Create one key per environment and workload, grant only sending access when possible, verify the sender domain before testing, inject the secret only into trusted server-side runtimes, and use message IDs and delivery events to verify results.
The simplest rule is the most important: if a user can view the code, inspect the network request, or read the repository, they must not be able to see the email API key. Build the sending path on the server, rotate keys without downtime, and treat any exposed key as compromised.
FAQ
Where do I find my email API key?
Open your email provider dashboard and look for API Keys, API Tokens, or Server Tokens. Create a new key for the specific environment and workload rather than reusing an existing broad-access credential. Many providers display the full secret only once, so store it in your secret manager immediately.
Can I use an email API key in frontend JavaScript?
No. Do not place a sending key in browser JavaScript, a public mobile application, or any variable exposed to the client. Send the request from a backend endpoint, serverless function, or trusted worker instead.
Why does my email API key work but email is not delivered?
The key may be valid while the sender domain is unverified, the From address is not authorized, the recipient is suppressed, the message bounced, or a mailbox provider filtered the email. Check the provider’s message activity and the received message headers—not just the API response.
How often should I rotate an email API key?
Rotate immediately after any suspected exposure. For normal operations, use a documented rotation cadence that your team can perform without downtime, and remove keys that are no longer assigned to an active service. Your provider may not automatically expire old keys.
What should I do if I committed an email API key to GitHub?
Revoke the exposed key immediately, create and deploy a replacement, inspect provider logs for unauthorized activity, and then remove the secret from the repository and its history as appropriate. Do not assume that deleting the secret in a follow-up commit makes it safe.