API Reference
Simple email API. Resend-compatible. One line to switch.
https://api.emailmate.devWe export a Resend class. Just change from 'resend' tofrom 'emailmate'. No other changes needed.
Authentication
Authenticate your API requests by including your API key in the Authorization header. You can create API keys in the dashboard.
curl https://api.emailmate.dev/emails \
-H "Authorization: Bearer em_xxxxxxxxxxxx" \
-H "Content-Type: application/json"Keep your API key secret. Never expose it in client-side code or commit it to version control.
Emails
Send transactional emails programmatically.
/v1/emailsSend an email
Request Body
| Parameter | Type | Description |
|---|---|---|
fromrequired | string | Sender email address. Format: "Name <email@domain.com>" |
torequired | string | string[] | Recipient email address(es) |
subjectrequired | string | Email subject line |
html | string | HTML content of the email |
text | string | Plain text version of the email |
reply_to | string | string[] | Reply-to email address(es) |
cc | string | string[] | CC recipients |
bcc | string | string[] | BCC recipients |
attachments | Attachment[] | File attachments |
headers | object | Custom email headers |
tags | Tag[] | Email tags for tracking |
Example Request
curl -X POST https://api.emailmate.dev/emails \
-H "Authorization: Bearer em_xxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{
"from": "Acme <onboarding@acme.com>",
"to": "user@example.com",
"subject": "Welcome to Acme",
"html": "<h1>Welcome!</h1><p>Thanks for signing up.</p>"
}'Response
{
"id": "em_xxxxxxxxxxxxxxxx",
"object": "email"
}/v1/emails/:idRetrieve an email by ID
Path Parameters
| Parameter | Type | Description |
|---|---|---|
idrequired | string | The email ID |
Response
{
"id": "em_xxxxxxxxxxxxxxxx",
"object": "email",
"to": ["user@example.com"],
"from": "onboarding@acme.com",
"subject": "Welcome to Acme",
"html": "<h1>Welcome!</h1>",
"created_at": "2024-01-01T00:00:00.000Z",
"last_event": "delivered"
}Domains
Manage sending domains for your emails.
/v1/domainsAdd a new domain
| Parameter | Type | Description |
|---|---|---|
namerequired | string | Domain name (e.g., acme.com) |
region | string | AWS SES region. Options: "us-east-1", "eu-west-1" |
/v1/domainsList all domains
Response
{
"data": [
{
"id": "dom_xxxxxxxx",
"name": "acme.com",
"status": "verified",
"created_at": "2024-01-01T00:00:00.000Z",
"records": [...]
}
]
}/v1/domains/:idGet domain details including DNS records
| Parameter | Type | Description |
|---|---|---|
idrequired | string | Domain ID |
/v1/domains/:id/verifyVerify domain DNS records
| Parameter | Type | Description |
|---|---|---|
idrequired | string | Domain ID |
/v1/domains/:idDelete a domain
| Parameter | Type | Description |
|---|---|---|
idrequired | string | Domain ID |
API Keys
Create and manage API keys for authentication.
/v1/api-keysCreate a new API key
| Parameter | Type | Description |
|---|---|---|
namerequired | string | A name to identify the key |
permission | string | "full_access" or "sending_access" |
/v1/api-keysList all API keys
Response
{
"data": [
{
"id": "key_xxxxxxxx",
"name": "Production",
"created_at": "2024-01-01T00:00:00.000Z"
}
]
}/v1/api-keys/:idDelete an API key
| Parameter | Type | Description |
|---|---|---|
idrequired | string | API key ID |
Audiences
Manage contact lists for marketing emails.
/v1/audiencesCreate an audience
| Parameter | Type | Description |
|---|---|---|
namerequired | string | Audience name |
/v1/audiencesList all audiences
Response
{
"data": [
{
"id": "aud_xxxxxxxx",
"name": "Newsletter",
"created_at": "2024-01-01T00:00:00.000Z"
}
]
}/v1/audiences/:idGet audience details
| Parameter | Type | Description |
|---|---|---|
idrequired | string | Audience ID |
/v1/audiences/:idDelete an audience
| Parameter | Type | Description |
|---|---|---|
idrequired | string | Audience ID |
Contacts
Manage contacts within audiences.
/v1/audiences/:audience_id/contactsAdd a contact to an audience
| Parameter | Type | Description |
|---|---|---|
emailrequired | string | Contact email address |
first_name | string | First name |
last_name | string | Last name |
unsubscribed | boolean | Unsubscribe status |
/v1/audiences/:audience_id/contactsList contacts in an audience
| Parameter | Type | Description |
|---|---|---|
audience_idrequired | string | Audience ID |
/v1/audiences/:audience_id/contacts/:idGet a contact
| Parameter | Type | Description |
|---|---|---|
audience_idrequired | string | Audience ID |
idrequired | string | Contact ID |
/v1/audiences/:audience_id/contacts/:idUpdate a contact
| Parameter | Type | Description |
|---|---|---|
first_name | string | First name |
last_name | string | Last name |
unsubscribed | boolean | Unsubscribe status |
/v1/audiences/:audience_id/contacts/:idRemove a contact
| Parameter | Type | Description |
|---|---|---|
audience_idrequired | string | Audience ID |
idrequired | string | Contact ID |
Templates
Create and manage email templates.
/v1/templatesCreate a template
| Parameter | Type | Description |
|---|---|---|
namerequired | string | Template name |
subjectrequired | string | Email subject |
htmlrequired | string | HTML content |
/v1/templatesList all templates
Response
{
"data": [
{
"id": "tpl_xxxxxxxx",
"name": "Welcome Email",
"created_at": "2024-01-01T00:00:00.000Z"
}
]
}/v1/templates/:idGet template details
| Parameter | Type | Description |
|---|---|---|
idrequired | string | Template ID |
/v1/templates/:idUpdate a template
| Parameter | Type | Description |
|---|---|---|
name | string | Template name |
subject | string | Email subject |
html | string | HTML content |
/v1/templates/:idDelete a template
| Parameter | Type | Description |
|---|---|---|
idrequired | string | Template ID |
Webhooks
Receive real-time notifications for email events.
Event Types
email.sentemail.deliveredemail.openedemail.clickedemail.bouncedemail.complainedWebhook Payload
{
"type": "email.delivered",
"created_at": "2024-01-01T00:00:00.000Z",
"data": {
"email_id": "em_xxxxxxxx",
"from": "onboarding@acme.com",
"to": ["user@example.com"],
"subject": "Welcome to Acme"
}
}Suppression List
Email addresses that are automatically blocked from receiving emails. This protects your sender reputation.
Why emails get suppressed
Email address doesn't exist or domain is invalid. Permanent failure.
Recipient marked your email as spam. Serious reputation risk.
Recipient clicked unsubscribe link. Honor their preference.
Added manually by you or your team.
Important: Sending to suppressed addresses will fail immediately with a clear error. This is by design - continuing to send to invalid addresses damages your sender reputation.
/v1/suppressionList suppressed email addresses
Query Parameters
| Parameter | Type | Description |
|---|---|---|
reason | string | Filter by reason: "hard_bounce", "complaint", "unsubscribe", "manual" |
limit | number | Max results to return (default 100) |
Response
{
"data": [
{
"id": "sup_xxxxxxxx",
"email": "bounced@invalid.com",
"reason": "hard_bounce",
"created_at": "2024-01-01T00:00:00.000Z"
}
]
}/v1/suppressionAdd an email to suppression list
| Parameter | Type | Description |
|---|---|---|
emailrequired | string | Email address to suppress |
reason | string | Optional reason (defaults to "manual") |
/v1/suppression/:idRemove an email from suppression list
| Parameter | Type | Description |
|---|---|---|
idrequired | string | Suppression entry ID |
Warning: Removing hard bounces or complaints may hurt your sender reputation if you send to them again.
Rate Limits
API rate limits and resource limits depend on your plan.
| Plan | Emails | Domains | API Keys | Log Retention | Overage |
|---|---|---|---|---|---|
| Free | 100/day | 1 | 1 | 7 days | — |
| Pro $9/mo | 10k/mo | 20 | 5 | 30 days | $0.40/1k |
| Scale $19/mo | 50k/mo | 50 | 15 | 90 days | $0.30/1k |
| BYOS Free | Your SES quota | 3 | 2 | 7 days | $0.10/1k (AWS) |
| BYOS Pro $5/mo | Your SES quota | 25 | 10 | 30 days | $0.10/1k (AWS) |
Rate limit headers are included in every response:
Plan Features
Features available by subscription plan. All plans include core email sending.
| Feature | Free | Pro $9 | Scale $19 | BYOS |
|---|---|---|---|---|
| Custom Templates Save and reuse email templates | — | ✓ | ✓ | Pro only |
| Webhooks Real-time delivery notifications | — | ✓ | ✓ | Pro only |
| Analytics Open rates, click tracking, insights | — | ✓ | ✓ | Pro only |
| Remove Branding No "Sent via EmailMate" footer | — | — | ✓ | — |
| Priority Support Fast response times, dedicated help | — | — | ✓ | — |
Feature Gating
Attempting to use a feature not available on your plan returns a clear error:
{
"error": {
"code": "feature_not_available",
"message": "Custom templates require Pro plan. Upgrade at /dashboard/settings",
"feature": "canUseCustomTemplates",
"required_plan": "pro"
}
}Check Features via API
Query your current plan features programmatically:
GET /v1/subscription
{
"plan": "pro",
"status": "active",
"features": {
"canUseCustomTemplates": true,
"canUseWebhooks": true,
"canUseAnalytics": true,
"canRemoveBranding": false,
"canUsePrioritySupport": false
},
"limits": {
"emailsPerMonth": 10000,
"domains": 20,
"apiKeys": 5
}
}Errors
Standard HTTP status codes with detailed error messages.
| Code | Description |
|---|---|
| 200 | Success |
| 400 | Bad request - Invalid parameters |
| 401 | Unauthorized - Invalid or missing API key |
| 403 | Forbidden - Insufficient permissions |
| 404 | Not found - Resource doesn't exist |
| 429 | Rate limit exceeded |
| 500 | Internal server error |
Error Codes
| Code | Description |
|---|---|
| invalid_api_key | API key is invalid or revoked |
| recipient_suppressed | Email address is on suppression list (bounced/complained) |
| account_paused | Your account is paused due to reputation issues |
| feature_not_available | Feature requires a higher plan |
| rate_limit_exceeded | Too many requests, slow down |
| quota_exceeded | Monthly email limit reached |
| domain_not_verified | Sending domain hasn't been verified |
| validation_error | Invalid parameters in request |
Error Response
{
"error": {
"code": "recipient_suppressed",
"message": "Email address is suppressed due to hard bounce",
"docs": "https://emailmate.dev/docs#suppression"
}
}Bring Your Own SES
Your AWS account. Your SES quota. Pay AWS directly at $0.10/1,000. We just give you the nice API and dashboard. Free forever.
What you get
- 90% cheaper - $0.10/1k vs Resend's $0.90/1k
- Your reputation - Build your own sending reputation, don't share it
- Your limits - Send as fast as your SES quota allows
- Unlimited everything - Domains, API keys, no artificial caps
Setup
- 1Create an IAM user in AWS with SES send permissions
- 2Go to Settings → Providers in your Emailmate dashboard
- 3Add your AWS Access Key ID, Secret Access Key, and region
- 4Verify your domain in SES and start sending
Required IAM Policy
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"ses:SendEmail",
"ses:SendRawEmail"
],
"Resource": "*"
}
]
}SDKs
New project? Use EmailMate. Coming from Resend? One line change.
Emailmate SDK
npm install emailmate
# or
bun add emailmateimport { EmailMate } from 'emailmate';
const emailmate = new EmailMate('em_xxxxxxxxxxxx');
await emailmate.emails.send({
from: 'Acme <hello@acme.com>',
to: 'user@example.com',
subject: 'Welcome to Acme',
html: '<h1>Welcome!</h1>'
});
// With React Email
import { WelcomeEmail } from './emails/welcome';
await emailmate.emails.send({
from: 'Acme <hello@acme.com>',
to: 'user@example.com',
subject: 'Welcome',
react: <WelcomeEmail name="John" />
});Migrating from Resend?
Our SDK exports a Resend class. Just change your import.
// Before
import { Resend } from 'resend';
// After - just change the import
import { Resend } from 'emailmate';
// Everything else stays exactly the same
const resend = new Resend('em_xxxxxxxxxxxx');
await resend.emails.send({
from: 'Acme <hello@acme.com>',
to: 'user@example.com',
subject: 'Hello',
html: '<p>World</p>'
});Other Languages
pip install emailmatego get github.com/emailmate/emailmate-gogem install emailmatecomposer require emailmate/emailmate-php