Emails API

Send single or bulk personalized emails with attachments using the Forma Mail API.

Try it live! Use the Interactive API Explorer for a full interactive experience with all endpoints.

Overview

The Emails API allows you to send template-based emails with:

  • Variable substitution - Personalize emails with dynamic content
  • Multiple recipients - Send to, CC, and BCC recipients
  • Attachments - Include PDF, Excel, or file attachments
  • Template-generated attachments - Dynamically create attachments from templates
  • Scheduling - Schedule emails for future delivery
  • Priority control - Set email priority (high, normal, low)
  • Bulk sending - Send personalized emails to up to 1,000 recipients

Base URL: https://api.formamail.com/api

Authentication: All endpoints require an API Key


Send Email

Send a single email using a template.

Endpoint

POST /emails/send

Headers

Authorization: Bearer YOUR_API_KEY
Content-Type: application/json

Request Body

FieldTypeRequiredDescription
templateIdstringYesUUID of the email template to use
versionstringNoTemplate version: published (default), draft, or version number
toarrayYesArray of recipient objects (email + optional name)
ccarrayNoArray of CC recipient objects
bccarrayNoArray of BCC recipient objects
replyTostringNoReply-to email address
variablesobjectYesVariables to populate the template
attachmentsarrayNoArray of attachment objects
prioritystringNoEmail priority: low, normal (default), high
scheduledAtstringNoISO 8601 datetime for scheduled sending
headersobjectNoCustom email headers (key-value pairs)
tagsarrayNoTags for categorization (max 50, alphanumeric/hyphen/underscore)
metadataobjectNoCustom metadata for tracking

Recipient Object

{
  "email": "user@example.com",
  "name": "John Doe"
}

Attachment Object

You can attach files in multiple ways:

Option 1: Base64 Content

{
  "filename": "invoice.pdf",
  "contentType": "application/pdf",
  "content": "JVBERi0xLjQK..."
}

Option 2: URL

{
  "filename": "report.pdf",
  "contentType": "application/pdf",
  "url": "https://example.com/files/report.pdf"
}

Option 3: Template-Generated (PDF/Excel)

{
  "filename": "invoice-{{invoiceNumber}}.pdf",
  "attachmentTemplateId": "template-uuid",
  "variables": {
    "invoiceNumber": "INV-001",
    "amount": 150.00
  },
  "outputFormats": ["pdf"]
}

Option 4: Asset Gallery

{
  "filename": "company-logo.png",
  "assetId": "asset-uuid"
}

Example Request

Basic Email

curl -X POST https://api.formamail.com/api/emails/send \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "templateId": "550e8400-e29b-41d4-a716-446655440000",
    "to": [
      {
        "email": "customer@example.com",
        "name": "Jane Smith"
      }
    ],
    "variables": {
      "firstName": "Jane",
      "orderNumber": "ORD-12345",
      "totalAmount": "$150.00",
      "orderDate": "2024-11-19"
    }
  }'

Email with PDF Attachment

curl -X POST https://api.formamail.com/api/emails/send \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "templateId": "550e8400-e29b-41d4-a716-446655440000",
    "to": [{
      "email": "customer@example.com",
      "name": "Jane Smith"
    }],
    "variables": {
      "firstName": "Jane",
      "invoiceNumber": "INV-2024-001"
    },
    "attachments": [{
      "filename": "invoice-{{invoiceNumber}}.pdf",
      "attachmentTemplateId": "660e8400-e29b-41d4-a716-446655440001",
      "variables": {
        "customerName": "Jane Smith",
        "invoiceNumber": "INV-2024-001",
        "amount": 299.99,
        "items": [
          {"name": "Product A", "qty": 2, "price": 99.99},
          {"name": "Product B", "qty": 1, "price": 100.00}
        ]
      },
      "outputFormats": ["pdf"]
    }]
  }'

Scheduled Email

curl -X POST https://api.formamail.com/api/emails/send \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "templateId": "550e8400-e29b-41d4-a716-446655440000",
    "to": [{"email": "customer@example.com"}],
    "variables": {"name": "Customer"},
    "scheduledAt": "2024-12-25T10:00:00Z",
    "priority": "high"
  }'

Response

Success (201 Created)

{
  "id": "770e8400-e29b-41d4-a716-446655440000",
  "messageId": "<1234567890@formamail.com>",
  "status": "queued",
  "recipientCount": 1,
  "attachmentCount": 1,
  "queuedAt": "2024-11-19T12:00:00.000Z",
  "estimatedDeliveryAt": "2024-11-19T12:00:30.000Z"
}

Response Fields:

FieldTypeDescription
idstringUnique email log ID
messageIdstringRFC 5322 message ID
statusstringEmail status: queued, scheduled, processing, sent, delivered, failed
recipientCountnumberTotal number of recipients (to + cc + bcc)
attachmentCountnumberTotal number of attachments
queuedAtstringTimestamp when email was queued
estimatedDeliveryAtstringEstimated delivery time

Try It

Ready to test this endpoint?


Bulk Personalized Send

Send personalized emails to multiple recipients (up to 1,000 per request).

Endpoint

POST /emails/send/bulk

Key Features

  • âś… Personalized variables per recipient
  • âś… Template-generated attachments (PDF/Excel) per recipient
  • âś… Base variables shared across all recipients
  • âś… Dry run mode for validation without sending
  • âś… Progress tracking with batch status endpoint
  • âś… Scheduling for future delivery

Request Body

FieldTypeRequiredDescription
templateIdstringYesEmail template UUID
versionstringNoTemplate version (default: published)
recipientsarrayYesArray of recipient objects (min: 1, max: 1000)
baseVariablesobjectNoVariables shared across all recipients
attachmentsarrayNoAttachments for all recipients
replyTostringNoReply-to email address
prioritystringNoPriority: low, normal, high
headersobjectNoCustom headers
tagsarrayNoTags for tracking
metadataobjectNoMetadata for tracking
batchNamestringNoName for this batch
dryRunbooleanNoValidate without sending (default: false)
scheduledAtstringNoSchedule for future delivery

Recipient Object (Bulk)

{
  "email": "customer@example.com",
  "name": "John Doe",
  "variables": {
    "firstName": "John",
    "invoiceNumber": "INV-001",
    "amount": 150.00,
    "items": [...]
  },
  "attachmentOverrides": [...]
}

Bulk Attachment Object

{
  "filename": "invoice-{{invoiceNumber}}.pdf",
  "attachmentTemplateId": "template-uuid",
  "baseVariables": {
    "companyName": "Acme Corp",
    "companyLogo": "https://example.com/logo.png"
  },
  "recipientVariableFields": ["invoiceNumber", "amount", "items"],
  "outputFormats": ["pdf"],
  "required": true
}

Example Requests

Basic Bulk Send

curl -X POST https://api.formamail.com/api/emails/send/bulk \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "templateId": "550e8400-e29b-41d4-a716-446655440000",
    "baseVariables": {
      "companyName": "Acme Corp",
      "supportEmail": "support@acme.com",
      "year": 2024
    },
    "recipients": [
      {
        "email": "customer1@example.com",
        "name": "John Doe",
        "variables": {
          "firstName": "John",
          "orderNumber": "ORD-001",
          "amount": 99.99
        }
      },
      {
        "email": "customer2@example.com",
        "name": "Jane Smith",
        "variables": {
          "firstName": "Jane",
          "orderNumber": "ORD-002",
          "amount": 149.99
        }
      }
    ],
    "batchName": "Monthly Newsletter - November 2024"
  }'

Bulk with Template-Generated PDFs

curl -X POST https://api.formamail.com/api/emails/send/bulk \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "templateId": "email-template-uuid",
    "baseVariables": {
      "companyName": "Acme Corp",
      "companyAddress": "123 Business St",
      "taxRate": 0.08
    },
    "attachments": [{
      "filename": "invoice-{{invoiceNumber}}.pdf",
      "attachmentTemplateId": "invoice-template-uuid",
      "baseVariables": {
        "companyLogo": "https://acme.com/logo.png",
        "footer": "Thank you for your business!"
      },
      "recipientVariableFields": ["invoiceNumber", "customerInfo", "items", "total"],
      "outputFormats": ["pdf"],
      "required": true
    }],
    "recipients": [
      {
        "email": "customer1@example.com",
        "name": "John Doe",
        "variables": {
          "firstName": "John",
          "invoiceNumber": "INV-2024-001",
          "customerInfo": {
            "name": "John Doe",
            "address": "456 Customer Lane",
            "phone": "+1-555-0001"
          },
          "items": [
            {"description": "Product A", "quantity": 2, "price": 50.00},
            {"description": "Product B", "quantity": 1, "price": 75.00}
          ],
          "total": 175.00
        }
      },
      {
        "email": "customer2@example.com",
        "name": "Jane Smith",
        "variables": {
          "firstName": "Jane",
          "invoiceNumber": "INV-2024-002",
          "customerInfo": {
            "name": "Jane Smith",
            "address": "789 Client Road",
            "phone": "+1-555-0002"
          },
          "items": [
            {"description": "Product C", "quantity": 3, "price": 100.00}
          ],
          "total": 300.00
        }
      }
    ],
    "batchName": "Monthly Invoices - November 2024",
    "tags": ["invoices", "billing", "automated"]
  }'

Dry Run (Validation Only)

curl -X POST https://api.formamail.com/api/emails/send/bulk \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "templateId": "550e8400-e29b-41d4-a716-446655440000",
    "recipients": [{...}, {...}],
    "dryRun": true
  }'

Response

Success (201 Created)

{
  "batchId": "880e8400-e29b-41d4-a716-446655440000",
  "totalEmails": 100,
  "status": "queued",
  "message": "Successfully queued 100 emails for sending",
  "createdAt": "2024-11-19T12:00:00.000Z",
  "estimatedCompletionAt": "2024-11-19T12:05:00.000Z"
}

Dry Run Response

{
  "valid": true,
  "totalEmails": 100,
  "totalQuotaCost": 150,
  "costBreakdown": {
    "emails": 100,
    "attachments": 50
  },
  "quotaStatus": {
    "emailQuota": {
      "used": 850,
      "limit": 1000,
      "remaining": 150
    },
    "attachmentQuota": {
      "used": 320,
      "limit": 500,
      "remaining": 180
    }
  },
  "recipientValidation": {
    "totalRecipients": 100,
    "validEmails": 98,
    "invalidEmails": 2
  },
  "templateValidation": {
    "templateFound": true,
    "templateType": "email",
    "requiredVariables": ["firstName", "orderNumber"],
    "missingVariables": []
  },
  "warnings": [
    "2 recipients have invalid email addresses and will be skipped"
  ]
}

Try It

Ready to test this endpoint?


Get Batch Status

Track the progress of a bulk email batch.

Endpoint

GET /emails/batch/:batchId/status

Example

curl https://api.formamail.com/api/emails/batch/880e8400-e29b-41d4-a716-446655440000/status \
  -H "Authorization: Bearer YOUR_API_KEY"

Response

{
  "batchId": "880e8400-e29b-41d4-a716-446655440000",
  "batchName": "Monthly Newsletter - November 2024",
  "status": "processing",
  "totalEmails": 100,
  "sent": 75,
  "delivered": 70,
  "failed": 2,
  "queued": 20,
  "processing": 5,
  "progress": 75,
  "queuedAt": "2024-11-19T12:00:00.000Z",
  "startedAt": "2024-11-19T12:00:10.000Z",
  "completedAt": null
}

Batch Status Values:

  • queued - Batch is waiting to be processed
  • processing - Emails are being sent
  • completed - All emails sent (successfully or failed)
  • cancelled - Batch was cancelled
  • scheduled - Batch is scheduled for future sending

Cancel Batch

Cancel a queued or processing batch.

Endpoint

POST /emails/batch/:batchId/cancel

Example

curl -X POST https://api.formamail.com/api/emails/batch/880e8400-e29b-41d4-a716-446655440000/cancel \
  -H "Authorization: Bearer YOUR_API_KEY"

Response

{
  "batchId": "880e8400-e29b-41d4-a716-446655440000",
  "status": "cancelled",
  "message": "Batch cancelled successfully. 20 emails were not sent.",
  "totalEmails": 100,
  "sent": 75,
  "cancelled": 20,
  "failed": 5
}

Get Email Details

Retrieve details of a single email by ID.

Endpoint

GET /emails/:id

Example

curl https://api.formamail.com/api/emails/770e8400-e29b-41d4-a716-446655440000 \
  -H "Authorization: Bearer YOUR_API_KEY"

Response

{
  "id": "770e8400-e29b-41d4-a716-446655440000",
  "messageId": "<1234567890@formamail.com>",
  "status": "delivered",
  "emailTemplateName": "Order Confirmation",
  "recipientCount": 1,
  "attachmentCount": 1,
  "queuedAt": "2024-11-19T12:00:00.000Z",
  "processingAt": "2024-11-19T12:00:05.000Z",
  "sentAt": "2024-11-19T12:00:10.000Z",
  "deliveredAt": "2024-11-19T12:00:15.000Z",
  "metadata": {
    "recipients": {
      "to": [{"email": "customer@example.com", "name": "Jane Smith"}],
      "cc": [],
      "bcc": []
    },
    "variables": {
      "firstName": "Jane",
      "orderNumber": "ORD-12345"
    },
    "attachments": [...]
  },
  "createdAt": "2024-11-19T12:00:00.000Z",
  "updatedAt": "2024-11-19T12:00:15.000Z"
}

Query Emails

Query and filter email logs with pagination.

Endpoint

GET /emails?page=1&limit=20&status=delivered&startDate=2024-11-01

Query Parameters

ParameterTypeDescription
pagenumberPage number (default: 1)
limitnumberItems per page (default: 20, max: 100)
statusstringFilter by status
templateIdstringFilter by template
startDatestringFilter from date (ISO 8601)
endDatestringFilter to date (ISO 8601)
searchstringSearch recipients or subject

Example

curl "https://api.formamail.com/api/emails?page=1&limit=20&status=delivered" \
  -H "Authorization: Bearer YOUR_API_KEY"

Response

{
  "data": [
    {
      "id": "770e8400-e29b-41d4-a716-446655440000",
      "status": "delivered",
      "emailTemplateName": "Order Confirmation",
      "recipientCount": 1,
      "sentAt": "2024-11-19T12:00:10.000Z",
      "deliveredAt": "2024-11-19T12:00:15.000Z"
    }
  ],
  "meta": {
    "page": 1,
    "limit": 20,
    "total": 150,
    "totalPages": 8
  }
}

Retry Failed Email

Retry sending a failed email.

Endpoint

POST /emails/:id/retry

Example

curl -X POST https://api.formamail.com/api/emails/770e8400-e29b-41d4-a716-446655440000/retry \
  -H "Authorization: Bearer YOUR_API_KEY"

Response

{
  "id": "770e8400-e29b-41d4-a716-446655440000",
  "status": "queued",
  "message": "Email queued for retry",
  "retryCount": 1,
  "queuedAt": "2024-11-19T13:00:00.000Z"
}

Code Examples

Node.js / JavaScript

const axios = require('axios');
 
const client = axios.create({
  baseURL: 'https://api.formamail.com/api',
  headers: {
    'Authorization': `Bearer ${process.env.FORMA_MAIL_API_KEY}`,
    'Content-Type': 'application/json'
  }
});
 
// Send single email
async function sendEmail() {
  const response = await client.post('/emails/send', {
    templateId: 'your-template-id',
    to: [{ email: 'user@example.com', name: 'John Doe' }],
    variables: {
      firstName: 'John',
      orderNumber: 'ORD-12345'
    }
  });
 
  console.log('Email sent:', response.data.id);
  return response.data;
}
 
// Send bulk personalized emails
async function sendBulkEmails() {
  const response = await client.post('/emails/send/bulk', {
    templateId: 'your-template-id',
    baseVariables: {
      companyName: 'Acme Corp'
    },
    recipients: [
      {
        email: 'customer1@example.com',
        variables: { firstName: 'John', orderNumber: 'ORD-001' }
      },
      {
        email: 'customer2@example.com',
        variables: { firstName: 'Jane', orderNumber: 'ORD-002' }
      }
    ],
    batchName: 'Order Confirmations'
  });
 
  console.log('Batch queued:', response.data.batchId);
 
  // Poll for status
  const batchId = response.data.batchId;
  const status = await client.get(`/emails/batch/${batchId}/status`);
  console.log('Batch progress:', status.data.progress + '%');
 
  return response.data;
}

Python

import requests
import os
 
API_KEY = os.getenv('FORMA_MAIL_API_KEY')
BASE_URL = 'https://api.formamail.com/api'
 
headers = {
    'Authorization': f'Bearer {API_KEY}',
    'Content-Type': 'application/json'
}
 
# Send single email
def send_email():
    response = requests.post(
        f'{BASE_URL}/emails/send',
        headers=headers,
        json={
            'templateId': 'your-template-id',
            'to': [{'email': 'user@example.com', 'name': 'John Doe'}],
            'variables': {
                'firstName': 'John',
                'orderNumber': 'ORD-12345'
            }
        }
    )
 
    result = response.json()
    print(f"Email sent: {result['id']}")
    return result
 
# Send bulk personalized emails
def send_bulk_emails():
    response = requests.post(
        f'{BASE_URL}/emails/send/bulk',
        headers=headers,
        json={
            'templateId': 'your-template-id',
            'baseVariables': {'companyName': 'Acme Corp'},
            'recipients': [
                {
                    'email': 'customer1@example.com',
                    'variables': {'firstName': 'John', 'orderNumber': 'ORD-001'}
                },
                {
                    'email': 'customer2@example.com',
                    'variables': {'firstName': 'Jane', 'orderNumber': 'ORD-002'}
                }
            ],
            'batchName': 'Order Confirmations'
        }
    )
 
    result = response.json()
    print(f"Batch queued: {result['batchId']}")
 
    # Poll for status
    batch_id = result['batchId']
    status_response = requests.get(
        f'{BASE_URL}/emails/batch/{batch_id}/status',
        headers=headers
    )
    status = status_response.json()
    print(f"Batch progress: {status['progress']}%")
 
    return result

Error Responses

All errors return a structured response:

{
  "statusCode": 400,
  "code": "VALIDATION_ERROR",
  "message": "Invalid request data",
  "timestamp": "2024-11-19T12:00:00.000Z",
  "path": "/api/emails/send",
  "errors": [
    {
      "field": "to",
      "message": "At least one recipient is required"
    }
  ]
}

Common Errors

StatusCodeDescriptionSolution
400VALIDATION_ERRORInvalid request dataCheck request format and required fields
401UNAUTHORIZEDMissing or invalid API keyInclude valid API key in Authorization header
404TEMPLATE_NOT_FOUNDTemplate ID not foundVerify template exists and you have access
429RATE_LIMIT_EXCEEDEDToo many requestsWait and retry with exponential backoff
429QUOTA_EXCEEDEDMonthly quota exceededUpgrade plan or wait for quota reset
500INTERNAL_ERRORServer errorContact support if persists

Best Practices

âś… DO

  • Use dry run for bulk sends to validate before sending
  • Include meaningful tags for easier tracking and filtering
  • Store email IDs for tracking and retry logic
  • Handle rate limits with exponential backoff
  • Monitor batch progress for large bulk sends
  • Use base variables for shared data in bulk sends
  • Set appropriate priority based on email importance
  • Test with small batches before scaling up

❌ DON’T

  • Don’t exceed 1,000 recipients per bulk request
  • Don’t send without testing templates first
  • Don’t ignore quota warnings - monitor usage
  • Don’t retry immediately on rate limit errors
  • Don’t hardcode template IDs - use environment variables
  • Don’t send to unverified domains in production

Next Steps


Back to API Reference