Email API Documentation

The Email API service provides a robust, multi-provider email delivery system with campaign management, bulk sending capabilities, and webhook event processing.

Base URL

  • Production: https://email.api.eventjuicer.com
  • Development: Your local or staging URL

Table of Contents


Authentication

All API requests require authentication via an API key. The API key should be included in the request body for email sending operations.

{ "api_key": "your-mailgun-or-resend-api-key", "driver": "mailgun" }

Endpoints

Send Single Email

Send a single email to one or multiple recipients.

Endpoint: POST /api/email/send

Request Body:

{ "driver": "mailgun", "api_key": "your-api-key", "from": "sender@example.com", "from_name": "Sender Name", "to": "recipient@example.com", "subject": "Hello {{name}}!", "html": "<h1>Hi {{name}}, your code is {{code}}</h1>", "text": "Hi {{name}}, your code is {{code}}", "replyTo": "reply@example.com", "cc": ["cc@example.com"], "bcc": ["bcc@example.com"], "tags": ["tag1", "tag2"], "variables": { "name": "John Doe", "code": "12345" }, "metadata": { "campaign_id": 123, "participant_id": 456, "custom_field": "tracking_value" } }

Parameters:

FieldTypeRequiredDescription
driverstringYesEmail provider: mailgun or resend
api_keystringYesProvider API key
fromstringYesSender email address
from_namestringNoSender display name
tostring | string[]YesRecipient email address(es)
subjectstringYesEmail subject
htmlstringYes*HTML email content
textstringYes*Plain text content
replyTostringNoReply-to email address
ccstring | string[]NoCC recipients
bccstring | string[]NoBCC recipients
tagsstring[]NoTags for tracking
variablesobjectNoVariables for template substitution ({{var}})
metadataobjectNoMetadata for webhook tracking (returned in webhooks)

*At least one of html or text is required.

Template Variables vs Metadata:

  • variables: Used for replacing {{placeholders}} in email content (subject, HTML, text)
  • metadata: Tracking data that comes back in webhook events (not visible in email)

Response:

{ "success": true, "driverName": "mailgun", "externalId": "msg-123456", "message": "Email sent successfully", "recipients": 1 }

cURL Example:

curl -X POST https://email.api.eventjuicer.com/api/email/send \ -H "Content-Type: application/json" \ -d '{ "driver": "mailgun", "api_key": "your-api-key", "from": "noreply@example.com", "to": "user@example.com", "subject": "Welcome!", "html": "<h1>Welcome to our service!</h1>" }'

Send Bulk Emails

Send personalized emails to multiple recipients with template variable substitution.

Endpoint: POST /api/email/bulk

Request Body:

{ "driver": "mailgun", "api_key": "your-api-key", "from": "sender@example.com", "from_name": "Sender Name", "subject": "Hello {{name}}!", "html": "<h1>Hi {{name}}</h1><p>Your code is: {{code}}</p>", "text": "Hi {{name}}, your code is: {{code}}", "recipients": [ { "email": "user1@example.com", "variables": { "name": "Alice", "code": "ABC123" }, "metadata": { "participant_id": 101 } }, { "email": "user2@example.com", "variables": { "name": "Bob", "code": "XYZ789" }, "metadata": { "participant_id": 102 } } ], "metadata": { "campaign_id": 456 }, "tags": ["bulk-send", "campaign-2024"] }

Note: When using recipient_ids instead of recipients, the API automatically adds participant_id to each recipient's metadata.

Parameters:

FieldTypeRequiredDescription
driverstringYesEmail provider: mailgun or resend
api_keystringYesProvider API key
fromstringYesSender email address
from_namestringNoSender display name
subjectstringYesEmail subject (supports {{variables}})
htmlstringYes*HTML content (supports {{variables}})
textstringYes*Plain text (supports {{variables}})
recipientsarrayYes*Array of recipient objects
recipients[].emailstringYesRecipient email
recipients[].variablesobjectNoPer-recipient template variables
recipients[].metadataobjectNoPer-recipient webhook metadata
recipient_idsnumber[]Yes*Array of participant IDs (auto-resolves to recipients)
metadataobjectNoTemplate-level metadata (applies to all recipients)
tagsstring[]NoTags for tracking

*Either recipients or recipient_ids is required.

Automatic Metadata:

  • When using recipient_ids, the API automatically adds participant_id to metadata for each recipient
  • Template metadata is merged with recipient metadata (recipient takes precedence)
  • Webhook events will contain both campaign_id and participant_id for easy database lookups

Response:

{ "success": true, "driverName": "mailgun", "totalEmails": 2, "message": "Bulk email sent successfully" }

Variable Substitution:

Use {{variableName}} in your subject, HTML, and text content. Each recipient can have different variable values.


Campaign Management

Create and send email campaigns with queue-based processing.

Create Campaign

Endpoint: POST /api/email/campaigns

Request Body:

{ "driver": "mailgun", "api_key": "your-api-key", "name": "Newsletter March 2024", "from": "newsletter@example.com", "template_subject": "March Newsletter", "template_url": "https://example.com/templates/newsletter.html", "recipients": [ { "email": "user1@example.com" }, { "email": "user2@example.com" } ] }

Response:

{ "success": true, "campaign": { "uuid": "550e8400-e29b-41d4-a716-446655440000", "name": "Newsletter March 2024", "status": "pending", "recipients_count": 2 } }

Send Campaign

Endpoint: POST /api/email/campaigns/{uuid}/send

Response:

{ "success": true, "message": "Campaign processing started", "batches": 1, "totalRecipients": 2 }

Email Templates

Validate external email templates before sending.

Endpoint: POST /api/email/templates

Request Body:

{ "template_url": "https://example.com/templates/welcome.html" }

Response:

{ "valid": true, "size": 12543, "preview": "<!DOCTYPE html>..." }

Webhooks

The API provides unified webhook endpoints for receiving email events from both Mailgun and Resend.

Webhook Endpoints

  • Mailgun: POST /api/webhooks/mailgun
  • Resend: POST /api/webhooks/resend

Webhook Configuration

Configure these URLs in your email provider's dashboard:

Mailgun:

https://email.api.eventjuicer.com/api/webhooks/mailgun

Resend:

https://email.api.eventjuicer.com/api/webhooks/resend

Webhook Events

All webhooks are verified with cryptographic signatures and normalized to standard event types:

Event TypeDescription
sentEmail was sent successfully
deliveredEmail was delivered to recipient's mail server
openedRecipient opened the email
clickedRecipient clicked a link in the email
bouncedEmail bounced (hard bounce)
failedEmail failed to send
complainedRecipient marked email as spam
unsubscribedRecipient unsubscribed
delayedEmail delivery was delayed (soft bounce)

Webhook Payload

Both providers send standardized webhook payloads:

{ "id": "evt_123456", "type": "delivered", "timestamp": 1234567890000, "messageId": "msg-abc123", "recipient": "user@example.com", "sender": "noreply@example.com", "subject": "Welcome Email", "tags": ["welcome", "onboarding"], "metadata": { "campaign_id": 123, "participant_id": 456, "custom_field": "value" }, "raw": {} }

Using Metadata to Track Emails

The metadata field in webhook events allows you to create email tracking records without storing provider message IDs:

Example: Creating EmailRecipient records from webhooks

// In your webhook handler async function processEmailEvent(event: WebhookEvent) { const { campaign_id, participant_id } = event.metadata || {}; if (!campaign_id || !participant_id) { console.warn('Missing metadata in webhook event'); return; } // Create or update EmailRecipient record await db.emailRecipient.upsert({ where: { campaign_id_participant_id: { campaign_id, participant_id } }, create: { campaign_id, participant_id, recipient: event.recipient, status: event.type, sent_at: event.type === 'sent' ? new Date(event.timestamp) : null, delivered_at: event.type === 'delivered' ? new Date(event.timestamp) : null, opened_at: event.type === 'opened' ? new Date(event.timestamp) : null, clicked_at: event.type === 'clicked' ? new Date(event.timestamp) : null, bounced_at: event.type === 'bounced' ? new Date(event.timestamp) : null, }, update: { status: event.type, delivered_at: event.type === 'delivered' ? new Date(event.timestamp) : undefined, opened_at: event.type === 'opened' ? new Date(event.timestamp) : undefined, clicked_at: event.type === 'clicked' ? new Date(event.timestamp) : undefined, bounced_at: event.type === 'bounced' ? new Date(event.timestamp) : undefined, } }); }

Automatic Metadata in Campaigns:

  • Campaign sends automatically include campaign_id in metadata
  • When using recipient_ids, each recipient automatically gets participant_id in metadata
  • No need to manually track provider message IDs!

Security

Mailgun Webhooks:

  • Uses HMAC-SHA256 signature verification
  • Signature included in webhook payload
  • Set MAILGUN_WEBHOOK_SIGNING_KEY environment variable

Resend Webhooks:

  • Uses Svix-compatible HMAC-SHA256 signature verification
  • Requires headers: svix-id, svix-timestamp, svix-signature
  • Set RESEND_WEBHOOK_SECRET environment variable

Supported Email Providers

Mailgun

Features:

  • Batch sending up to 1,000 recipients per API call
  • Template variable substitution
  • Webhook events for delivery tracking
  • EU and US regions supported

Configuration:

{ "driver": "mailgun", "api_key": "your-mailgun-api-key" }

Required Environment Variables:

  • MAILGUN_API_KEY - API key from Mailgun
  • MAILGUN_DOMAIN - Your verified domain
  • MAILGUN_WEBHOOK_SIGNING_KEY - For webhook verification (optional)

Resend

Features:

  • Batch sending up to 100 recipients per API call
  • Template variable substitution
  • Webhook events via Svix
  • Modern API with great developer experience

Configuration:

{ "driver": "resend", "api_key": "your-resend-api-key" }

Required Environment Variables:

  • RESEND_API_KEY - API key from Resend
  • RESEND_WEBHOOK_SECRET - For webhook verification (optional)

Error Handling

The API uses standard HTTP status codes and returns detailed error messages.

Error Response Format

{ "error": "Error message", "details": "Detailed error description" }

Common Status Codes

CodeDescription
200Success
400Bad Request - Invalid parameters
401Unauthorized - Invalid webhook signature
500Server Error - Processing failed

Common Errors

Invalid Email Address:

{ "error": "Invalid email addresses", "invalidEmails": ["invalid-email"] }

Missing Required Fields:

{ "error": "driver, api_key, from, to, subject, and text or html are required" }

Webhook Verification Failed:

{ "error": "Invalid webhook signature" }

Rate Limits

Rate limits depend on your email provider's plan:

Mailgun:

  • Foundation: 50,000 emails/month
  • Growth: 100,000 emails/month
  • Scale: Custom limits

Resend:

  • Free: 100 emails/day, 3,000/month
  • Pro: 50,000 emails/month
  • Enterprise: Custom limits

Best Practices

  1. Use Bulk Endpoint for Multiple Recipients

    • More efficient than individual sends
    • Better for campaigns and newsletters
  2. Implement Webhook Handlers

    • Track delivery status
    • Handle bounces and complaints
    • Monitor engagement metrics
  3. Use Tags for Organization

    • Group emails by campaign
    • Track performance by category
    • Filter analytics data
  4. Handle Errors Gracefully

    • Implement retry logic for failed sends
    • Log errors for debugging
    • Monitor API responses
  5. Validate Email Addresses

    • Check format before sending
    • Remove bounced addresses
    • Maintain clean email lists

Support

For issues or questions:

  • Check the GitHub repository
  • Review webhook logs in your email provider dashboard
  • Monitor API response codes and error messages

Changelog

v1.0.0 (2024)

  • Initial release
  • Support for Mailgun and Resend
  • Single and bulk email sending
  • Campaign management
  • Unified webhook processing
  • Standardized event types