API Reference

Simple email API. Resend-compatible. One line to switch.

Base URL
https://api.emailmate.dev
Coming from Resend?

We 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.

POST/v1/emails

Send an email

Request Body

ParameterTypeDescription
fromrequiredstringSender email address. Format: "Name <email@domain.com>"
torequiredstring | string[]Recipient email address(es)
subjectrequiredstringEmail subject line
htmlstringHTML content of the email
textstringPlain text version of the email
reply_tostring | string[]Reply-to email address(es)
ccstring | string[]CC recipients
bccstring | string[]BCC recipients
attachmentsAttachment[]File attachments
headersobjectCustom email headers
tagsTag[]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"
}
GET/v1/emails/:id

Retrieve an email by ID

Path Parameters

ParameterTypeDescription
idrequiredstringThe 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.

POST/v1/domains

Add a new domain

ParameterTypeDescription
namerequiredstringDomain name (e.g., acme.com)
regionstringAWS SES region. Options: "us-east-1", "eu-west-1"
GET/v1/domains

List all domains

Response

{
  "data": [
    {
      "id": "dom_xxxxxxxx",
      "name": "acme.com",
      "status": "verified",
      "created_at": "2024-01-01T00:00:00.000Z",
      "records": [...]
    }
  ]
}
GET/v1/domains/:id

Get domain details including DNS records

ParameterTypeDescription
idrequiredstringDomain ID
POST/v1/domains/:id/verify

Verify domain DNS records

ParameterTypeDescription
idrequiredstringDomain ID
DELETE/v1/domains/:id

Delete a domain

ParameterTypeDescription
idrequiredstringDomain ID

API Keys

Create and manage API keys for authentication.

POST/v1/api-keys

Create a new API key

ParameterTypeDescription
namerequiredstringA name to identify the key
permissionstring"full_access" or "sending_access"
GET/v1/api-keys

List all API keys

Response

{
  "data": [
    {
      "id": "key_xxxxxxxx",
      "name": "Production",
      "created_at": "2024-01-01T00:00:00.000Z"
    }
  ]
}
DELETE/v1/api-keys/:id

Delete an API key

ParameterTypeDescription
idrequiredstringAPI key ID

Audiences

Manage contact lists for marketing emails.

POST/v1/audiences

Create an audience

ParameterTypeDescription
namerequiredstringAudience name
GET/v1/audiences

List all audiences

Response

{
  "data": [
    {
      "id": "aud_xxxxxxxx",
      "name": "Newsletter",
      "created_at": "2024-01-01T00:00:00.000Z"
    }
  ]
}
GET/v1/audiences/:id

Get audience details

ParameterTypeDescription
idrequiredstringAudience ID
DELETE/v1/audiences/:id

Delete an audience

ParameterTypeDescription
idrequiredstringAudience ID

Contacts

Manage contacts within audiences.

POST/v1/audiences/:audience_id/contacts

Add a contact to an audience

ParameterTypeDescription
emailrequiredstringContact email address
first_namestringFirst name
last_namestringLast name
unsubscribedbooleanUnsubscribe status
GET/v1/audiences/:audience_id/contacts

List contacts in an audience

ParameterTypeDescription
audience_idrequiredstringAudience ID
GET/v1/audiences/:audience_id/contacts/:id

Get a contact

ParameterTypeDescription
audience_idrequiredstringAudience ID
idrequiredstringContact ID
PATCH/v1/audiences/:audience_id/contacts/:id

Update a contact

ParameterTypeDescription
first_namestringFirst name
last_namestringLast name
unsubscribedbooleanUnsubscribe status
DELETE/v1/audiences/:audience_id/contacts/:id

Remove a contact

ParameterTypeDescription
audience_idrequiredstringAudience ID
idrequiredstringContact ID

Templates

Create and manage email templates.

POST/v1/templates

Create a template

ParameterTypeDescription
namerequiredstringTemplate name
subjectrequiredstringEmail subject
htmlrequiredstringHTML content
GET/v1/templates

List all templates

Response

{
  "data": [
    {
      "id": "tpl_xxxxxxxx",
      "name": "Welcome Email",
      "created_at": "2024-01-01T00:00:00.000Z"
    }
  ]
}
GET/v1/templates/:id

Get template details

ParameterTypeDescription
idrequiredstringTemplate ID
PATCH/v1/templates/:id

Update a template

ParameterTypeDescription
namestringTemplate name
subjectstringEmail subject
htmlstringHTML content
DELETE/v1/templates/:id

Delete a template

ParameterTypeDescription
idrequiredstringTemplate ID

Webhooks

Receive real-time notifications for email events.

Event Types

email.sent
email.delivered
email.opened
email.clicked
email.bounced
email.complained

Webhook 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

Hard Bounce

Email address doesn't exist or domain is invalid. Permanent failure.

Complaint

Recipient marked your email as spam. Serious reputation risk.

Unsubscribe

Recipient clicked unsubscribe link. Honor their preference.

Manual

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.

GET/v1/suppression

List suppressed email addresses

Query Parameters

ParameterTypeDescription
reasonstringFilter by reason: "hard_bounce", "complaint", "unsubscribe", "manual"
limitnumberMax 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"
    }
  ]
}
POST/v1/suppression

Add an email to suppression list

ParameterTypeDescription
emailrequiredstringEmail address to suppress
reasonstringOptional reason (defaults to "manual")
DELETE/v1/suppression/:id

Remove an email from suppression list

ParameterTypeDescription
idrequiredstringSuppression 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.

PlanEmailsDomainsAPI KeysLog RetentionOverage
Free100/day117 days
Pro $9/mo10k/mo20530 days$0.40/1k
Scale $19/mo50k/mo501590 days$0.30/1k
BYOS FreeYour SES quota327 days$0.10/1k (AWS)
BYOS Pro $5/moYour SES quota251030 days$0.10/1k (AWS)

Rate limit headers are included in every response:

X-RateLimit-Limit: 10
X-RateLimit-Remaining: 9
X-RateLimit-Reset: 1704067200

Plan Features

Features available by subscription plan. All plans include core email sending.

FeatureFreePro $9Scale $19BYOS
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.

CodeDescription
200Success
400Bad request - Invalid parameters
401Unauthorized - Invalid or missing API key
403Forbidden - Insufficient permissions
404Not found - Resource doesn't exist
429Rate limit exceeded
500Internal server error

Error Codes

CodeDescription
invalid_api_keyAPI key is invalid or revoked
recipient_suppressedEmail address is on suppression list (bounced/complained)
account_pausedYour account is paused due to reputation issues
feature_not_availableFeature requires a higher plan
rate_limit_exceededToo many requests, slow down
quota_exceededMonthly email limit reached
domain_not_verifiedSending domain hasn't been verified
validation_errorInvalid 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

  1. 1Create an IAM user in AWS with SES send permissions
  2. 2Go to Settings → Providers in your Emailmate dashboard
  3. 3Add your AWS Access Key ID, Secret Access Key, and region
  4. 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.

Recommended

Emailmate SDK

npm install emailmate
# or
bun add emailmate
import { 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" />
});
1 line change

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

Python
pip install emailmate
Go
go get github.com/emailmate/emailmate-go
Ruby
gem install emailmate
PHP
composer require emailmate/emailmate-php