> ## Documentation Index
> Fetch the complete documentation index at: https://docs.sendpost.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Send Email

> Send transactional or marketing emails to one or multiple recipients. This is the primary endpoint for all email sending through SendPost.

**Capabilities:**
- **Single Email**: Send to one recipient with full personalization
- **Batch Sending**: Send to up to 500 recipients in a single API call
- **Personalization**: Use Handlebars templating (`{{variableName}}`) in subject, HTML body, and text body
- **Attachments**: Include base64-encoded files (max 25MB total per request)
- **Tracking**: Enable/disable open and click tracking per email
- **IP Pool Routing**: Route emails through specific IP pools

**Common Use Cases:**

| Use Case | Example |
|----------|---------|
| Order Confirmation | Send receipt with order details after purchase |
| Password Reset | Time-sensitive security email with reset link |
| Welcome Email | Onboard new users with personalized greeting |
| Shipping Notification | Update customers when orders ship |
| Invoice/Receipt | Attach PDF invoices to billing emails |

**Personalization Example:**
```json
{
  "to": [{
    "email": "john@example.com",
    "customFields": {
      "firstName": "John",
      "orderTotal": "$99.99"
    }
  }],
  "subject": "Hi {{firstName}}, your order is confirmed!",
  "htmlBody": "<p>Thanks {{firstName}}! Your total: {{orderTotal}}</p>"
}
```

**Test Email Addresses:**

SendPost provides special test email addresses for testing webhooks and events without sending real emails:

| Test Email | Behavior |
|------------|----------|
| `test@playwithsendpost.io` | Generates delivered event, then simulates opens and clicks after a few seconds |
| `deliver@playwithsendpost.io` | Generates delivered event only (no opens/clicks) |
| `hardbounce@playwithsendpost.io` | Always generates a hard bounce event |
| `softbounce@playwithsendpost.io` | Always generates a soft bounce event |
| `dropped@playwithsendpost.io` | Always generates a dropped event (SMTPDropped) |

**Self-Test Email (Send to Yourself):**

Use `hello@playwithsendpost.io` as the **from** address to send emails to yourself for testing:

- **Sender**: Must be `hello@playwithsendpost.io`
- **Recipient**: Must be your account owner email (the email you used to sign up)
- **Behavior**: Real email delivery to your inbox (no domain verification required, no mock mode)
- **Use Case**: Test your API integration by sending real emails to yourself without domain setup

**Example:**
```json
{
  "from": {"email": "hello@playwithsendpost.io"},
  "to": [{"email": "your-account-email@example.com"}],
  "subject": "Test Email to Myself",
  "htmlBody": "<p>This is a test email to myself</p>"
}
```
This will send a real email to your inbox that you can actually receive and open.

**Note**: If you send to any email other than your account email, the request will be rejected with an error.

**Using Test Emails:**
- Simply send to any test email address like a normal recipient
- Mock mode is automatically enabled for test emails
- All events trigger webhooks normally
- Events are marked as mock messages but follow the same structure as real events
- Perfect for testing webhook integrations without using real email addresses

**Example:**
```json
{
  "to": [{"email": "test@playwithsendpost.io"}],
  "from": {"email": "sender@example.com"},
  "subject": "Test Email",
  "htmlBody": "<p>This is a test</p>"
}
```
This will generate: Sent → Delivered → Opened (after 2-5s) → Clicked (after 1-3s more)

**Response:** Returns an array of responses, one per recipient, each containing:
- `messageId` - Unique ID for tracking
- `submittedAt` - Timestamp of acceptance
- `errorCode` and `message` - Status information




## OpenAPI

````yaml post /subaccount/email/
openapi: 3.1.0
info:
  title: SendPost API
  version: 1.4.0
  description: >
    # Introduction


    > ### 📌 API versioning & the v1 response contract

    >

    > This reference documents the **v1 response contract** — the stable,
    camelCase

    > response shape that SendPost commits to. This is the shape you should
    build against.

    >

    > **During the current deprecation window**, requests authenticated with an
    account

    > or sub-account API key receive the **legacy** response shape by default,
    so existing

    > integrations keep working unchanged. To receive the documented v1 shape
    today, send:

    >

    > ```

    > X-SendPost-Public-Contract: v1

    > ```

    >

    > **How to tell which shape you got.** Every public response echoes the
    applied

    > contract in the `X-SendPost-Public-Contract` response header. While the
    legacy

    > shape is being served, responses also carry standard deprecation signals:

    > `Deprecation: true`, a `Sunset` header with the exact cut-over date, and a

    > `Link: <...>; rel="deprecation"` header pointing at the migration guide.
    **Read the

    > `Sunset` header for the authoritative end date** rather than hardcoding
    one.

    >

    > **After the sunset date**, v1 becomes the default and the legacy shape is
    no longer

    > served. New integrations should send `X-SendPost-Public-Contract: v1` now
    and rely on

    > the shapes in this reference.


    SendPost provides email API and SMTP relay which can be used not just to
    send & measure but also alert & optimised email sending.


    You can use SendPost to:


    * Send personalised emails to multiple recipients using email API 


    * Track opens and clicks


    * Analyse statistics around open, clicks, bounce, unsubscribe and spam 



    At and advanced level you can use it to:


    * Manage multiple sub-accounts which may map to your promotional or
    transactional sending, multiple product lines or multiple customers 


    * Classify your emails using groups for better analysis


    * Analyse and fix email sending at sub-account level, IP Pool level or group
    level


    * Have automated alerts to notify disruptions regarding email sending


    * Manage different dedicated IP Pools so to better control your email
    sending


    * Automatically know when IP or domain is blacklisted or sender score is
    down


    * Leverage pro deliverability tools to get significantly better email
    deliverability & inboxing



    [<img src="https://run.pstmn.io/button.svg" alt="Run In Postman"
    style="width: 128px; height:
    32px;">](https://god.gw.postman.com/run-collection/33476323-e6dbd27f-c4a7-4d49-bcac-94b0611b938b?action=collection%2Ffork&source=rip_markdown&collection-url=entityId%3D33476323-e6dbd27f-c4a7-4d49-bcac-94b0611b938b%26entityType%3Dcollection%26workspaceId%3D6b1e4f65-96a9-4136-9512-6266c852517e) 


    # Overview


    ## REST API


    SendPost API is built on REST API principles. Authenticated users can
    interact with any of the API endpoints to perform:


    * **GET**- to get a resource


    * **POST** - to create a resource


    * **PUT** - to update an existing resource


    * **DELETE** - to delete a resource



    The API endpoint for all API calls is:

    <code>https://api.sendpost.io/api/v1</code>



    Some conventions that have been followed in the API design overall are
    following:



    * All resources have either <code>/api/v1/subaccount</code> or
    <code>/api/v1/account</code> in their API call resource path based on who is
    authorised for the resource. All API calls with path
    <code>/api/v1/subaccount</code> use <code>X-SubAccount-ApiKey</code> in
    their request header. Likewise all API calls with path
    <code>/api/v1/account</code> use <code>X-Account-ApiKey</code> in their
    request header.


    * All resource endpoints end with singular name and not plural. So we have
    <code>domain</code> instead of domains for domain resource endpoint.
    Likewise we have <code>sender</code> instead of senders for sender resource
    endpoint.


    * Body submitted for POST / PUT API calls as well as JSON response from
    SendPost API follow camelcase convention


    * All timestamps returned in response (created or submittedAt response
    fields) are UNIX nano epoch timestamp.



    <aside class="success">

    All resources have either <code>/api/v1/subaccount</code> or
    <code>/api/v1/account</code> in their API call resource path based on who is
    authorised for the resource. All API calls with path
    <code>/api/v1/subaccount</code> use <code>X-SubAccount-ApiKey</code> in
    their request header. Likewise all API calls with path
    <code>/api/v1/account</code> use <code>X-Account-ApiKey</code> in their
    request header.

    </aside>



    SendPost uses conventional HTTP response codes to indicate the success or
    failure of an API request. 



    * Codes in the <code>2xx</code> range indicate success. 


    * Codes in the <code>4xx</code> range indicate an error owing due to
    unauthorize access, incorrect request parameters or body etc.


    * Code in the <code>5xx</code> range indicate an eror with SendPost's
    servers ( internal service issue or maintenance )



    <aside class="info">

    SendPost all responses return <code>created</code> in UNIX nano epoch
    timestamp. 

    </aside>



    ## Authentication


    SendPost uses API keys for authentication. You can register a new SendPost
    API key at our [developer portal](https://app.sendpost.io/register).



    SendPost expects the API key to be included in all API requests to the
    server in a header that looks like the following:



    `X-SubAccount-ApiKey: AHEZEP8192SEGH`



    This API key is used for all Sub-Account level operations such as:


    * Sending emails


    * Retrieving stats regarding open, click, bounce, unsubscribe and spam


    * Uploading suppressions list


    * Verifying sending domains

    and more


    In addition to <code>X-SubAccount-ApiKey</code> you also have another API
    Key <code>X-Account-APIKey</code> which is used for Account level operations
    such as :


    * Creating and managing sub-accounts


    * Allocating IPs for your account


    * Getting overall billing and usage information


    * Email List validation


    * Creating and managing alerts

    and more



    <aside class="notice">

    You must look at individual API reference page to look at whether
    <code>X-SubAccount-ApiKey</code> is required or
    <code>X-Account-ApiKey</code>

    </aside>



    In case an incorrect API Key header is specified or if it is missed you will
    get HTTP Response 401 ( Unauthorized ) response from SendPost.



    ## HTTP Response Headers



    Code           | Reason                 | Details

    ---------------| -----------------------| -----------

    200            | Success                | Everything went well

    401            | Unauthorized           | Incorrect or missing API header
    either <code>X-SubAccount-ApiKey</code> or <code>X-Account-ApiKey</code>

    403            | Forbidden              | Typically sent when resource with
    same name or details already exist

    406            | Missing resource id    | Resource id specified is either
    missing or doesn't exist

    422            | Unprocessable entity   | Request body is not in proper
    format

    500            | Internal server error  | Some error happened at SendPost
    while processing API request

    503            | Service Unavailable    | SendPost is offline for
    maintenance. Please try again later


    # API SDKs


    We have native SendPost SDKs in the following programming languages. You can
    integrate with them or create your own SDK with our API specification. In
    case you need any assistance with respect to API then do reachout to our
    team from website chat or email us at **hello@sendpost.io**



    * [PHP](https://github.com/sendpost/sendpost_php_sdk)


    * [Javascript](https://github.com/sendpost/sendpost_javascript_sdk)


    * [Ruby](https://github.com/sendpost/sendpost_ruby_sdk)


    * [Python](https://github.com/sendpost/sendpost_python_sdk)


    * [Golang](https://github.com/sendpost/sendpost_go_sdk)



    # API Reference


    SendX REST API can be broken down into two major sub-sections:



    * Sub-Account


    * Account 



    Sub-Account API operations enable common email sending API use-cases like
    sending bulk email, adding new domains or senders for email sending
    programmatically, retrieving stats, adding suppressions etc. All Sub-Account
    API operations need to pass <code>X-SubAccount-ApiKey</code> header with
    every API call.



    The Account API operations allow users to manage multiple sub-accounts and
    manage IPs. A single parent SendPost account can have 100's of sub-accounts.
    You may want to create sub-accounts for different products your company is
    running or to segregate types of emails or for managing email sending across
    multiple customers of yours.



    # SMTP Reference


    Simple Mail Transfer Protocol (SMTP) is a quick and easy way to send email
    from one server to another. SendPost provides an SMTP service that allows
    you to deliver your email via our servers instead of your own client or
    server. 

    This means you can count on SendPost's delivery at scale for your SMTP
    needs. 



    ## Integrating SMTP 



    1. Get the SMTP `username` and `password` from your SendPost account.


    2. Set the server host in your email client or application to
    `smtp.sendpost.io`. This setting is sometimes referred to as the external
    SMTP server or the SMTP relay.


    3. Set the `username` and `password`.


    4. Set the port to `587` (or as specified below).


    ## SMTP Ports



    - For an unencrypted or a TLS connection, use port `25`, `2525` or `587`.


    - For a SSL connection, use port `465`


    - Check your firewall and network to ensure they're not blocking any of our
    SMTP Endpoints.



    SendPost supports STARTTLS for establishing a TLS-encrypted connection.
    STARTTLS is a means of upgrading an unencrypted connection to an encrypted
    connection. There are versions of STARTTLS for a variety of protocols; the
    SMTP version is defined in [RFC 3207](https://www.ietf.org/rfc/rfc3207.txt).



    To set up a STARTTLS connection, the SMTP client connects to the SendPost
    SMTP endpoint `smtp.sendpost.io` on port 25, 587, or 2525, issues an EHLO
    command, and waits for the server to announce that it supports the STARTTLS
    SMTP extension. The client then issues the STARTTLS command, initiating TLS
    negotiation. When negotiation is complete, the client issues an EHLO command
    over the new encrypted connection, and the SMTP session proceeds normally.



    <aside class="success">

    If you are unsure which port to use, a TLS connection on port 587 is
    typically recommended.

    </aside>



    ## Sending email from your application



    ```javascript

    "use strict";


    const nodemailer = require("nodemailer");


    async function main() {

    // create reusable transporter object using the default SMTP transport

    let transporter = nodemailer.createTransport({

    host: "smtp.sendpost.io",

    port: 587,

    secure: false, // true for 465, false for other ports

    auth: {

    user:  "<username>" , // generated ethereal user

    pass: "<password>", // generated ethereal password

    },

    requireTLS: true,

    debug: true,

    logger: true,

    });


    // send mail with defined transport object

    try {

    let info = await transporter.sendMail({

    from: 'erlich@piedpiper.com',

    to: 'gilfoyle@piedpiper.com',

    subject: 'Test Email Subject',

    html: '<h1>Hello Geeks!!!</h1>',

    });

    console.log("Message sent: %s", info.messageId);

    } catch (e) {

    console.log(e)

    }

    }


    main().catch(console.error);

    ```


    For PHP



    ```php

    <?php

    // Import PHPMailer classes into the global namespace

    use PHPMailer\PHPMailer\PHPMailer;

    use PHPMailer\PHPMailer\SMTP;

    use PHPMailer\PHPMailer\Exception;


    // Load Composer's autoloader

    require 'vendor/autoload.php';


    $mail = new PHPMailer(true);


    // Settings

    try {

    $mail->SMTPDebug = SMTP::DEBUG_CONNECTION;                  // Enable
    verbose debug output

    $mail->isSMTP();                                            // Send using
    SMTP

    $mail->Host       = 'smtp.sendpost.io';                     // Set the SMTP
    server to send through

    $mail->SMTPAuth   = true;                                   // Enable SMTP
    authentication

    $mail->Username   = '<username>';                           // SMTP username

    $mail->Password   = '<password>';                           // SMTP password

    $mail->SMTPSecure = PHPMailer::ENCRYPTION_STARTTLS;         // Enable
    implicit TLS encryption

    $mail->Port       = 587;                                    // TCP port to
    connect to; use 587 if you have set `SMTPSecure =
    PHPMailer::ENCRYPTION_STARTTLS`


    //Recipients

    $mail->setFrom('erlich@piedpiper.com', 'Erlich');

    $mail->addAddress('gilfoyle@piedpiper.com', 'Gilfoyle');


    //Content

    $mail->isHTML(true);                                  //Set email format to
    HTML

    $mail->Subject = 'Here is the subject';

    $mail->Body    = 'This is the HTML message body <b>in bold!</b>';

    $mail->AltBody = 'This is the body in plain text for non-HTML mail clients';


    $mail->send();

    echo 'Message has been sent';


    } catch (Exception $e) {

    echo "Message could not be sent. Mailer Error: {$mail->ErrorInfo}";

    }

    ```

    For Python

    ```python

    #!/usr/bin/python3


    import sys

    import os

    import re


    from smtplib import SMTP

    import ssl


    from email.mime.text import MIMEText


    SMTPserver = 'smtp.sendpost.io'

    PORT = 587

    sender =     'erlich@piedpiper.com'

    destination = ['gilfoyle@piedpiper.com']


    USERNAME = "<username>"

    PASSWORD = "<password>"


    # typical values for text_subtype are plain, html, xml

    text_subtype = 'plain'


    content="""\

    Test message

    """


    subject="Sent from Python"


    try:

    msg = MIMEText(content, text_subtype)

    msg['Subject']= subject

    msg['From']   = sender


    conn = SMTP(SMTPserver, PORT)

    conn.ehlo()

    context = ssl.create_default_context()

    conn.starttls(context=context)  # upgrade to tls

    conn.ehlo()

    conn.set_debuglevel(True)

    conn.login(USERNAME, PASSWORD)


    try:

    resp = conn.sendmail(sender, destination, msg.as_string())

    print("Send Mail Response: ", resp)

    except Exception as e:

    print("Send Email Error: ", e)

    finally:

    conn.quit()


    except Exception as e:

    print("Error:", e)

    ```

    For Golang

    ```go

    package main


    import (

    "fmt"

    "net/smtp"

    "os"

    )


    // Sending Email Using Smtp in Golang


    func main() {


    username := "<username>"

    password := "<password>"


    from := "erlich@piedpiper.com"

    toList := []string{"gilfoyle@piedpiper.com"}

    host := "smtp.sendpost.io"

    port := "587" // recommended


    // This is the message to send in the mail

    msg := "Hello geeks!!!"


    // We can't send strings directly in mail,

    // strings need to be converted into slice bytes

    body := []byte(msg)


    // PlainAuth uses the given username and password to

    // authenticate to host and act as identity.

    // Usually identity should be the empty string,

    // to act as username.

    auth := smtp.PlainAuth("", username, password, host)


    // SendMail uses TLS connection to send the mail

    // The email is sent to all address in the toList,

    // the body should be of type bytes, not strings

    // This returns error if any occured.

    err := smtp.SendMail(host+":"+port, auth, from, toList, body)


    // handling the errors

    if err != nil {

    fmt.Println(err)

    os.Exit(1)

    }


    fmt.Println("Successfully sent mail to all user in toList")

    }


    ```

    For Java

    ```java

    // implementation 'com.sun.mail:javax.mail:1.6.2'


    import java.util.Properties;


    import javax.mail.Message;

    import javax.mail.Session;

    import javax.mail.Transport;

    import javax.mail.internet.InternetAddress;

    import javax.mail.internet.MimeMessage;


    public class SMTPConnect {


    // This address must be verified.

    static final String FROM = "erlich@piedpiper.com";

    static final String FROMNAME = "Erlich Bachman";


    // Replace recipient@example.com with a "To" address. If your account

    // is still in the sandbox, this address must be verified.

    static final String TO = "gilfoyle@piedpiper.com";


    // Replace smtp_username with your SendPost SMTP user name.

    static final String SMTP_USERNAME = "<username>";


    // Replace smtp_password with your SendPost SMTP password.

    static final String SMTP_PASSWORD = "<password>";


    // SMTP Host Name

    static final String HOST = "smtp.sendpost.io";


    // The port you will connect to on SendPost SMTP Endpoint.

    static final int PORT = 587;


    static final String SUBJECT = "SendPost SMTP Test (SMTP interface accessed
    using Java)";


    static final String BODY = String.join(

    System.getProperty("line.separator"),

    "<h1>SendPost SMTP Test</h1>",

    "<p>This email was sent with SendPost using the ",

    "<a href='https://github.com/eclipse-ee4j/mail'>Javamail Package</a>",

    " for <a href='https://www.java.com'>Java</a>."

    );


    public static void main(String[] args) throws Exception {


    // Create a Properties object to contain connection configuration
    information.

    Properties props = System.getProperties();

    props.put("mail.transport.protocol", "smtp");

    props.put("mail.smtp.port", PORT);

    props.put("mail.smtp.starttls.enable", "true");

    props.put("mail.smtp.debug", "true");

    props.put("mail.smtp.auth", "true");


    // Create a Session object to represent a mail session with the specified
    properties.

    Session session = Session.getDefaultInstance(props);


    // Create a message with the specified information.

    MimeMessage msg = new MimeMessage(session);

    msg.setFrom(new InternetAddress(FROM,FROMNAME));

    msg.setRecipient(Message.RecipientType.TO, new InternetAddress(TO));

    msg.setSubject(SUBJECT);

    msg.setContent(BODY,"text/html");


    // Create a transport.

    Transport transport = session.getTransport();


    // Send the message.

    try {

    System.out.println("Sending...");


    // Connect to SendPost SMTP using the SMTP username and password you
    specified above.

    transport.connect(HOST, SMTP_USERNAME, SMTP_PASSWORD);


    // Send the email.

    transport.sendMessage(msg, msg.getAllRecipients());

    System.out.println("Email sent!");


    } catch (Exception ex) {


    System.out.println("The email was not sent.");

    System.out.println("Error message: " + ex.getMessage());

    System.out.println(ex);

    }

    // Close and terminate the connection.

    }

    }

    ```


    Many programming languages support sending email using SMTP. This capability
    might be built into the programming language itself, or it might be
    available as an add-on, plug-in, or library. You can take advantage of this
    capability by sending email through SendPost from within application
    programs that you write.


    We have provided examples in Python3, Golang, Java, PHP, JS.


    # API Contract Versioning (Public REST)


    The public REST API uses a versioned response contract so field changes stay
    non-breaking:


    * Send `X-SendPost-Public-Contract: v1` to opt into the current v1 response
    shape, or `legacy` for the pre-v1 shape. If the header is omitted, the
    applied contract is policy-driven — `legacy` before the published sunset
    date, `v1` after it.

    * Every response echoes `X-SendPost-Public-Contract: <applied>`. When the
    `legacy` contract is served, responses also include `Deprecation: true`,
    `Sunset: <RFC1123 date>`, and `Link: <doc-url>; rel="deprecation"`.

    * Migrate to `v1` before the sunset date. Notable legacy → v1 field changes:
    Suppression `smtp_error` → `smtpError`, Stat `email_type` → `emailType`.


    > `X-SendPost-Private-Api: true` is an internal header used only by the
    SendPost dashboard to receive richer internal objects. It is not part of the
    public SDK contract and should not be set by API integrations.
servers:
  - url: https://api.sendpost.io/api/v1
security: []
tags:
  - name: Email
    description: >
      This API allows you to send emails from a specific sub-account. You can
      specify one email recipient or multiple recipients with this API call. You
      can provide options for tracking opens or clicks, having dynamic custom
      fields or if-else conditions for email personalisation.


      You can also assign various groups to each API call which will later be
      useful while analysing stats. Also you can specify custom headers which
      will be added to webhook payload on occurrence of events such as email
      processed, delivered, opened, clicked, bounced, unsubscribed etc.


      If you are running on dedicated IP plan then you can also specify the
      IPPool from which emails should be sent.

      ## Personalisation within email

      SendPost allows users to personalize email content dynamically using
      Handlebars. Personalization can be applied to the text body, html body and
      the subject itself. Here's how you can utilize custom field variables to
      enhance your email communication.

      ```js

      {
        "from": {
          "email": "richard@piedpiper.com",
          "name": "Richard"
        },
        "to": [
          {
            "email": "gavin@hooli.com",
            "name": "Gavin Belson",
            "customFields": {
              "firstName": "Gavin",
              "discountCode": "BELSON240"
              "status": "VIP"
            }
          },
          {
            "email": "erlich@piedpiper.com",
            "name": "Erlich Bachman",
            "customFields": {
              "firstName": "Erlich",
              "discountCode" : "BACHMAN10"
              "status": "Incubator"
            }
          },
        ],
        "subject": "Hello, {{firstName}}! Welcome to Pied Piper!",
        "htmlBody": "<p>Hi {{firstName}},</p><p>Your discount code is <b>{{discountCode}}</b>. Your account status is {{status}}}.</p>",
        "textBody": "Hi {{firstName}},\n\nYour discount code is {{discountCode}}. Your account status is {{status}}.",
        "ippool": "default",
        "trackOpens": true,
        "trackClicks": true,
        "groups": [
          "special-offers"
        ]
      }

      ```


      ### Explanation:

      Custom Fields for Personalization:

      - Each recipient in the to array has a customFields map. 

      - These fields are used to dynamically render the email content.

      - Example: `{{firstName}}`, `{{discountCode}}`, and `{{status}}` in the
      subject, htmlBody, and textBody are replaced with the respective values
      from customFields.

      ### Output Example:


      For gavin@hooli.com:



      Subject: Hello, Gavin! Your Special Offer Awaits

      <p>Hi Gavin,</p><p>Your discount code is <b>BELSON240</b>. Your account
      status is VIP.</p>



      ---




      For erlich@piedpier.com:




      Subject: Hello, Erlich! Your Special Offer Awaits

      <p>Hi Erlich,</p><p>Your discount code is <b>BACHMAN10</b>. Your account
      status is Incubator.</p>



      ---


      ### Note: 

      <strong>`unsubscribe` is a reserved custom field name. You can't use it as
      a custom field name.</strong>


      ## Unsubscribe link in your templates

      Here is how to add an unsubscribe link to your SendPost email templates.

      Add this to your email template:


      ```


      <a href='{{unsubscribe}}'>Unsubscribe</a>

      ```


      Any user who clicks on this will get added to the suppression list on your
      SendPost subaccount.
  - name: Domain
    description: >
      This API allows you to manage your domains for a specific sub-account.
      Across all the requests you need to pass X-SubAccount-ApiKey header.
  - name: Stats
    description: >
      This API allows you to get your stats for a specific sub-account. Across
      all the requests you need to pass X-SubAccount-ApiKey header. You will be
      able to see email processed, delivered, opens, clicks, hardBounce,
      softBounce, unsubscribe and spam complaints.
  - name: Suppression
    description: >
      This API allows you to manage your suppressions for a specific
      sub-account. Across all the requests you need to pass X-SubAccount-ApiKey
      header.
  - name: IP
    description: >
      This API allows you to manage your ips for a specific account. Across all
      the requests you need to pass X-Account-ApiKey header.
  - name: IPPools
    description: >
      This API allows you to manage your ippools for a specific account. Across
      all the requests you need to pass X-Account-ApiKey header.

      ## Routing Strategies and Metadata


      ### routing_strategy 0 (RoundRobinStrategy)

      In RoundRobinStrategy all your emails are fairly shared between all your
      IPs and TPSPs


      The payload for routingMetaData for RoundRobinStrategy is:


      Key | Value

      --------- | -----------

      routingStrategy | 0

      routingMetaData | "{}"



      For example, if you have IP 3.238.19.86 and TPSPs Sendgrid and Mailgun and
      send 6 emails then 2 emails will be sent from 3.238.19.86, Mailgun and
      Sengrid.


      ### routing_strategy 1 (EmailProviderStrategy)


      In the EmailProviderStrategy we can assign IPs and TPSPs to the specific
      email provider.


      Existing email provider types:


      Id | Description

      --------- | -----------

      0 | Email provider Gmail

      1 | Email provider Yahoo

      2 | Email provider AOL

      3 | Email provider Microsoft

      4 | Email provider Comcast

      5 | Email provider Yandex

      6 | Email provider GMX

      7 | Email provider Mailru

      8 | Email provider Icloud

      9 | Email provider Zoho

      10 | Email provider QQ

      11 | Email provider default



      Key | Value

      --------- | -----------

      routingStrategy | 1

      routingMetaData | JSON payload


      JSON payload example:

      ```json

      {
        "0": "[\"IP_100\",\"IP_105\"]",
        "1": "[\"TPSP_101\"]",
        "others": "[\"IP_102\",\"TPSP_103\",\"IP_104\"]"
      } 

      ```



      On the left side, you can see the email types: 0 is Gmail, 1 is Yahoo, and
      'others' in this case all email addresses that don't belong to Yahoo or
      Gmail, the left side key is in the string format. Currently, for the right
      side, the format is an Array of strings in the format of "Entity_ID".
      Where 'Entity' could be 'IP' or 'TPSP' (third-party sending provider).


      For example, the 'IP_' prefix means that the entity is IP, and 100 in
      "IP_100" mean that the ID of this IP is 100. For example, the 'TPSP_'
      prefix means that the entity is TPSP, and 101 in "TPSP_101" mean that the
      ID of this TPSP is 101.


      The metadata above means: that for Gmail we send emails fairly between IPs
      with ID 105 and ID 100; and for Yahoo, we send emails from TPSP with ID
      101; and for all the rest email types we send fairly from the TPSP with ID
      103 and from IP with ID 104 and 102.


      ### routing_strategy 2 (VolumePercentageStrategy)


      In the VolumePercentageStrategy we can assign volumes to the specific IPs
      and TPSPs.


      Key | Value

      --------- | -----------

      routingStrategy | 2

      routingMetaData | JSON payload


      JSON payload example:


      ```json 

      {
        "IP_100":   "2",
        "IP_101":   "3",
        "TPSP_102": "1",
        "TPSP_103": "4"
      }

      ```

      Currently, for the left side, the format is a string in the format of
      "Entity_ID". Where 'Entity' could be 'IP' or 'TPSP' (third-party sending
      provider). And for the right side, the volume number of emails that we
      send (also in the string format).


      For example, the 'IP_' prefix means that the entity is IP, and 100 in
      "IP_100" mean that the ID of this IP is 100. For example, the 'TPSP_'
      prefix means that the entity is TPSP, and 101 in "TPSP_101" mean that the
      ID of this TPSP is 101.


      The metadata above means: that, for example, if we send 20 emails, 4 go
      from IP with ID 100, 6 go from IP with ID 101, 2 go from TPSP with ID 102,
      and 8 go from TPSP with ID 103.


      ### routing_strategy 3 (SendingDomainStrategy)

      In the SendingDomainStrategy we can assign IPs and TPSPs to the specific
      domains that we are sending from.


      Key | Value

      --------- | -----------

      routingStrategy | 3

      routingMetaData | JSON payload


      JSON payload example:

      ```json 

      {
        "sendx.io":    "[\"TPSP_100\",\"IP_105\"]",
        "sendpost.io": "[\"IP_101\"]",
        "others":      "[\"IP_102\",\"IP_103\",\"TPSP_104\"]"
      }

      ```


      On the left side, you can see the domains, in this case, it's sendx.io and
      sendpost.io, and 'others'. The email would be put in the 'others' category
      if its domain doesn't belong to sendx.io or sendpost.io. Currently, for
      the right side, the format is an Array of strings in the format of
      "Entity_ID". Where 'Entity' could be 'IP' or 'TPSP' (third-party sending
      provider).


      For example, the 'IP_' prefix means that the entity is IP, and 100 in
      "IP_100" mean that the ID of this IP is 100. For example, the 'TPSP_'
      prefix means that the entity is TPSP, and 101 in "TPSP_101" mean that the
      ID of this TPSP is 101.


      The metadata above means: that, for example, if we send emails from
      t1@sendx.io, t2@sendx.io, t1@sendpost.io, t1@gmail.com, t2@gmail.com,
      t3@gmail.com, t4@yahoo.com The sendx.io emails (t1@sendx.io, t2@sendx.io)
      will be sent from TPSP with ID 100 and IP with ID 105. The sendpost.io
      emails will be sent from IP with ID 101. The 'others' emails
      (t1@gmail.com, t2@gmail.com, t3@gmail.com, t4@yahoo.com) will be sent from
      IP with ID 102 and 103, and TPSP with ID 104.
  - name: Stats (A)
    description: >
      This API allows you to get your stats for a specific account. Across all
      the requests you need to pass X-Account-ApiKey header. You will be able to
      see email processed, delivered, opens, clicks, hardBounce, softBounce,
      unsubscribe and spam complaints for the specific account.
  - name: Sub-Account
    description: >
      This API allows you to manage your sub-accounts for a specific
      sub-account. Across all the requests you need to pass X-Account-ApiKey
      header.
  - name: Webhook
    description: >
      This API allows you to manage your webhooks for a specific account. Across
      all the requests you need to pass X-Account-ApiKey header.
  - name: Webhook Reference
    description: >
      Webhooks are an HTTP POST request made to your application endpoint when
      an interesting event happens at SendPost. This includes events such as
      email opens, clicks, hard bounce, spam, unsubscribe and more.


      You may want to consume webhook events if you want to replicate state of
      your email recipients to your internal system ( have they unsubscribed or
      has their email bounced ?) or you want to build custom analytics for
      internal product consumption.


      Other use cases where consuming webhook may be relevant is when you are
      building an application on top of SendPost such as an email marketing
      software and you want to show emails delivered, opened, clicked etc. to
      your customers.



      # Testing Webhooks


      Generally configuring a webhook is cumbersome process for developers.  At
      SendPost we have tried to make it a bit simpler:


      * **Webhook Single-Click Test**


      You can go to SendPost dashboard and click on button to test individual
      webhook. This will trigger a test Webhook API call of the specific event
      such as email open, click etc.


      * **Request Bin**


      [RequestBin](https://requestbin.com/) is a great service to inspect HTTP
      requests. You can create a temporary RequestBin URL and use the temporary
      URL as your webhook URL in SendPost.


      After that you can trigger webhook calls either using curl or through our
      Webhook Single-Click Test. RequestBin will then record the HTTP requests
      and allow you to inspect the HTTP requests to verify headers, JSON body,
      and other information about the webhook request.


      This will provide you with information about the HTTP requests used in the
      webhook if you don’t have a public URL set up yet and want to start
      developing right away.
  - name: Message
    description: >
      This API allows you to manage your messages for a specific account. Across
      all the requests you need to pass X-Account-ApiKey header.
paths:
  /subaccount/email/:
    post:
      tags:
        - Email
      summary: Send Email
      description: >
        Send transactional or marketing emails to one or multiple recipients.
        This is the primary endpoint for all email sending through SendPost.


        **Capabilities:**

        - **Single Email**: Send to one recipient with full personalization

        - **Batch Sending**: Send to up to 500 recipients in a single API call

        - **Personalization**: Use Handlebars templating (`{{variableName}}`) in
        subject, HTML body, and text body

        - **Attachments**: Include base64-encoded files (max 25MB total per
        request)

        - **Tracking**: Enable/disable open and click tracking per email

        - **IP Pool Routing**: Route emails through specific IP pools


        **Common Use Cases:**


        | Use Case | Example |

        |----------|---------|

        | Order Confirmation | Send receipt with order details after purchase |

        | Password Reset | Time-sensitive security email with reset link |

        | Welcome Email | Onboard new users with personalized greeting |

        | Shipping Notification | Update customers when orders ship |

        | Invoice/Receipt | Attach PDF invoices to billing emails |


        **Personalization Example:**

        ```json

        {
          "to": [{
            "email": "john@example.com",
            "customFields": {
              "firstName": "John",
              "orderTotal": "$99.99"
            }
          }],
          "subject": "Hi {{firstName}}, your order is confirmed!",
          "htmlBody": "<p>Thanks {{firstName}}! Your total: {{orderTotal}}</p>"
        }

        ```


        **Test Email Addresses:**


        SendPost provides special test email addresses for testing webhooks and
        events without sending real emails:


        | Test Email | Behavior |

        |------------|----------|

        | `test@playwithsendpost.io` | Generates delivered event, then simulates
        opens and clicks after a few seconds |

        | `deliver@playwithsendpost.io` | Generates delivered event only (no
        opens/clicks) |

        | `hardbounce@playwithsendpost.io` | Always generates a hard bounce
        event |

        | `softbounce@playwithsendpost.io` | Always generates a soft bounce
        event |

        | `dropped@playwithsendpost.io` | Always generates a dropped event
        (SMTPDropped) |


        **Self-Test Email (Send to Yourself):**


        Use `hello@playwithsendpost.io` as the **from** address to send emails
        to yourself for testing:


        - **Sender**: Must be `hello@playwithsendpost.io`

        - **Recipient**: Must be your account owner email (the email you used to
        sign up)

        - **Behavior**: Real email delivery to your inbox (no domain
        verification required, no mock mode)

        - **Use Case**: Test your API integration by sending real emails to
        yourself without domain setup


        **Example:**

        ```json

        {
          "from": {"email": "hello@playwithsendpost.io"},
          "to": [{"email": "your-account-email@example.com"}],
          "subject": "Test Email to Myself",
          "htmlBody": "<p>This is a test email to myself</p>"
        }

        ```

        This will send a real email to your inbox that you can actually receive
        and open.


        **Note**: If you send to any email other than your account email, the
        request will be rejected with an error.


        **Using Test Emails:**

        - Simply send to any test email address like a normal recipient

        - Mock mode is automatically enabled for test emails

        - All events trigger webhooks normally

        - Events are marked as mock messages but follow the same structure as
        real events

        - Perfect for testing webhook integrations without using real email
        addresses


        **Example:**

        ```json

        {
          "to": [{"email": "test@playwithsendpost.io"}],
          "from": {"email": "sender@example.com"},
          "subject": "Test Email",
          "htmlBody": "<p>This is a test</p>"
        }

        ```

        This will generate: Sent → Delivered → Opened (after 2-5s) → Clicked
        (after 1-3s more)


        **Response:** Returns an array of responses, one per recipient, each
        containing:

        - `messageId` - Unique ID for tracking

        - `submittedAt` - Timestamp of acceptance

        - `errorCode` and `message` - Status information
      operationId: sendEmail
      requestBody:
        description: Email message details
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/EmailMessageObject'
      responses:
        '200':
          description: A list of email message response objects.
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/EmailResponse'
        '400':
          description: >
            The request was rejected before any email was sent. The body is a
            single `EmailResponse` object, not an array. `errorCode` is 3 or 4
            when the `from` domain doesn't exist or isn't verified, and 11 when
            `tpspFrom` is invalid.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/EmailResponse'
              example:
                to: ''
                submittedAt: 1704067200000000000
                messageId: ''
                errorCode: 11
                message: >-
                  tpspFrom email must be on the same registered domain as from
                  email
      security:
        - subAccountAuth: []
      x-code-samples:
        - lang: js
          label: JavaScript
          source: |
            const { EmailApi, EmailMessage } = require('sendpost_js');
            const email = new EmailApi();
            const apiKey = 'your_api_key'; // {String} Sub-Account API Key

            (async function() {
              const message = new EmailMessage();
              message.from = { email: 'richard@piedpiper.com' };
              message.to = [{ email: 'gavin@hooli.com' }]
              message.subject = 'Hello'
              message.htmlBody = '<strong>it works!</strong>';
              message.ippool = 'PiedPiper'

              const opts = {
                emailMessage: message
              };
              try {
                const data = await email.sendEmail(apiKey, opts)
                console.log('API called successfully. Returned data: ', data);
              } catch (error) {
                console.error(error);
              }
            })()
        - lang: php
          label: PHP
          source: >
            require_once(__DIR__ . '/vendor/autoload.php');

            $client = new GuzzleHttp\Client();


            $apiInstance = new sendpost\api\EmailApi($client);


            $x_sub_account_api_key = 'your_api_key'; // string | Sub-Account API
            Key

            $email_message = new \sendpost\model\EmailMessage(); 

            $email_message->setSubject('Hello World');

            $email_message->setHtmlBody('<strong>it works!</strong>');

            $email_message->setIppool('PiedPiper');

            $from = new \sendpost\model\From();

            $from->setEmail('richard@piedpiper.com');


            $to = new \sendpost\model\To();

            $to->setEmail('gavin@hooli.com');

            $email_message->setTo(array($to));

            $email_message->setFrom($from);


            try {
                $result = $apiInstance->sendEmail($x_sub_account_api_key, $email_message);
                print_r($result);
            } catch (Exception $e) {
                echo 'Exception when calling EmailApi->sendEmail: ', $e->getMessage(), PHP_EOL;
            }
        - lang: python
          label: Python
          source: |
            import sendpost_python_sdk
            from pprint import pprint
            from sendpost_python_sdk.apis.tags import email_api

            # Enter a context with an instance of the API client
            with sendpost_python_sdk.ApiClient() as api_client:
                # Create an instance of the API class
                api_instance = email_api.EmailApi(api_client)
                x_sub_account_api_key = "your_api_key" # str | Sub-Account API Key
                email = {
                  "from": {
                        "email": "richard@piedpiper.com",
                  },
                  "to": [
                    {
                      "email": "gavin@hooli.com",
                    }
                  ],
                  "subject": "Hello World",
                  "htmlBody": "<strong>it works!</strong>",
                  "ippool": "PiedPiper",
                }
                try:
                    api_response = api_instance.send_email(header_params={ 'X-SubAccount-ApiKey': x_sub_account_api_key}, body=email)
                    pprint(api_response)
                except sendpost_python_sdk.ApiException as e:
                    print("Exception when calling EmailApi->send_email: %s\n" % e)
        - lang: ruby
          label: Ruby
          source: >
            require 'sendpost_ruby_sdk'


            api_instance = Sendpost::EmailApi.new

            x_sub_account_api_key = 'your_api_key' # String | Sub-Account API
            Key

            email_message = Sendpost::EmailMessage.new

            email_message.from = {
              email: 'richard@piedpiper.com'
            }

            email_message.to = [{
              email: 'gavin@hooli.com'
            }]

            email_message.subject = 'Hello World'

            email_message.html_body =  '<strong>it works!</strong>'

            email_message.ippool = 'PiedPiper'


            opts = {
              email_message: email_message # EmailMessage | Email message
            }


            begin
              result = api_instance.send_email(x_sub_account_api_key, opts)
              p result
            rescue Sendpost::ApiError => e
              puts "Exception when calling EmailApi->send_email: #{e}"
            end
        - lang: go
          label: Go
          source: |
            cfg := sendpost.NewConfiguration()
            client := sendpost.NewAPIClient(cfg)

            emailMessage := sendpost.EmailMessage{}
            emailMessage.SetSubject("Hello World")
            emailMessage.SetHtmlBody("<strong>it works!</strong>")
            emailMessage.SetIppool("PiedPiper")
            emailMessage.From = &sendpost.From{}
            emailMessage.From.SetEmail("richard@piedpiper.com")
            tos := make([]sendpost.To, 0)
            to := &sendpost.To{}
            to.SetEmail("gavin@hooli.com")
            tos = append(tos, *to)
            emailMessage.To = tos

            emailRequest := sendpost.ApiSendEmailRequest{}
            emailRequest = emailRequest.XSubAccountApiKey("your_api_key")
            emailRequest = emailRequest.EmailMessage(emailMessage)
            res, _, err := client.EmailApi.SendEmailExecute(emailRequest)
        - lang: shell
          label: cURL
          source: |
            curl -X POST "https://api.sendpost.io/api/v1/subaccount/email/" \
            -H "accept: application/json" \
            -H "X-SubAccount-ApiKey: your_api_key" \
            -d '{
              "from": { "email": "richard@piedpiper.com" },
              "to": [{ "email": "gavin@hooli.com" }],
              "subject": "Hello World",
              "htmlBody": "<strong>it works!</strong>",
              "ippool": "PiedPiper"
            }'
components:
  schemas:
    EmailMessageObject:
      type: object
      description: >
        Email message object containing all the details required to send an
        email.

        At minimum, you need to provide `from`, `to`, and either `subject` with
        `htmlBody`/`textBody` or a `template`.
      required:
        - from
        - to
      properties:
        from:
          $ref: '#/components/schemas/EmailAddress'
          description: The sender's email address and optional display name
        replyTo:
          $ref: '#/components/schemas/EmailAddress'
          description: >-
            The reply-to email address. If not specified, replies will go to the
            `from` address
        tpspFrom:
          $ref: '#/components/schemas/EmailAddress'
          description: >
            Optional sender for emails delivered through a third-party sending
            provider (TPSP): SendGrid, Amazon SES, Mailgun, SparkPost, Postmark,
            or Custom SMTP. For example, when sending over your SendPost warmup
            cap overflows to a TPSP pool, those emails go out as `tpspFrom`
            instead of `from`.


            - Must be on the same registered domain as `from`. For example,
            `from` on `agent1.example.com` and `tpspFrom` on
            `agent2.example.com`.

            - It doesn't need to be verified in SendPost, but it must be set up
            as a sender at the TPSP.

            - Emails delivered on SendPost IPs still go out as `from`. Stats and
            webhook events are always reported under `from`.

            - If `name` is omitted, the `from` name is used. If `replyTo` isn't
            set, replies go to `tpspFrom`.

            - If `tpspFrom` is invalid, the whole request is rejected with HTTP
            400 and `errorCode` 11.
        to:
          type: array
          description: >
            List of recipients. Each recipient can have their own CC, BCC, and
            custom fields for personalization.

            Maximum 1000 recipients per API call.
          items:
            $ref: '#/components/schemas/Recipient'
          minItems: 1
          maxItems: 1000
        subject:
          type: string
          description: >
            Email subject line. Supports Handlebars templating for
            personalization.

            Example: "Hello, {{firstName}}! Your order is ready"
          example: Welcome to SendPost, {{firstName}}!
          maxLength: 998
        preText:
          type: string
          description: >
            Preview text (preheader) shown in email clients before opening the
            email.

            This text appears after the subject line in most email clients'
            inbox view.
          example: Your weekly digest is here with 5 new updates...
          maxLength: 200
        htmlBody:
          type: string
          description: >
            HTML content of the email. Supports Handlebars templating for
            personalization.

            Use {{customFieldName}} to insert recipient-specific values.
          example: >-
            <html><body><h1>Hello {{firstName}}</h1><p>Welcome to our
            platform!</p></body></html>
        textBody:
          type: string
          description: >
            Plain text content of the email. Used as fallback when HTML cannot
            be rendered.

            Also improves deliverability as some spam filters prefer multipart
            emails.
          example: |-
            Hello {{firstName}},

            Welcome to our platform!

            Best regards,
            The Team
        ampBody:
          type: string
          description: >
            AMP HTML content for supported email clients (Gmail, Yahoo).

            Enables interactive email experiences like carousels, forms, and
            real-time content.

            See https://amp.dev/about/email/ for more details.
          example: <!doctype html><html ⚡4email><head>...</head><body>...</body></html>
        template:
          type: string
          description: >
            Name of a pre-defined template to use for this email.

            When specified, the template's subject, htmlBody, and textBody will
            be used

            unless explicitly overridden in this request.
          example: welcome-email-v2
        ippool:
          type: string
          description: >
            Name of the IP pool to use for sending this email.

            If not specified, the default IP pool for the sub-account will be
            used.
          example: transactional
        headers:
          type: object
          description: >
            Custom email headers to include in the message.

            Common uses: adding List-Unsubscribe headers, custom tracking IDs,
            or priority flags.

            Note: Some headers like From, To, Subject are set automatically and
            cannot be overridden.
          additionalProperties:
            type: string
          example:
            X-Custom-Header: custom-value
            X-Campaign-ID: summer-sale-2024
            List-Unsubscribe: <mailto:unsubscribe@example.com>
        trackOpens:
          type: boolean
          description: >
            Whether to track email opens using a tracking pixel.

            When enabled, a 1x1 transparent image is inserted into the HTML
            body.

            Default: true (if not specified)
          default: true
          example: true
        trackClicks:
          type: boolean
          description: >
            Whether to track link clicks by rewriting URLs through SendPost's
            tracking domain.

            When enabled, all links in htmlBody are replaced with tracking URLs.

            Default: true (if not specified)
          default: true
          example: true
        groups:
          type: array
          description: >
            Tags/groups to categorize this email for analytics and reporting.

            Use groups to segment your email statistics (e.g., by campaign,
            email type, or customer segment).
          items:
            type: string
          example:
            - transactional
            - order-confirmation
            - premium-customers
        attachments:
          type: array
          description: |
            File attachments to include with the email.
            Maximum total attachment size: 25MB.
            Supported formats: PDF, images, documents, etc.
          items:
            $ref: '#/components/schemas/Attachment'
        webhookEndpoint:
          type: string
          description: |
            Custom webhook URL to receive events for this specific email.
            Overrides the default webhook configured at the account level.
            Useful for per-email or per-customer webhook routing.
          format: uri
          example: https://your-app.com/webhooks/email-events
      example:
        from:
          email: notifications@yourcompany.com
          name: Your Company
        replyTo:
          email: support@yourcompany.com
          name: Support Team
        to:
          - email: customer@example.com
            name: John Doe
            customFields:
              firstName: John
              orderId: ORD-12345
              orderTotal: $99.99
        subject: Your order {{orderId}} has been shipped!
        htmlBody: >-
          <h1>Hi {{firstName}}</h1><p>Your order {{orderId}} worth
          {{orderTotal}} is on its way!</p>
        textBody: >-
          Hi {{firstName}}, Your order {{orderId}} worth {{orderTotal}} is on
          its way!
        ippool: transactional
        trackOpens: true
        trackClicks: true
        groups:
          - order-shipped
          - transactional
    EmailResponse:
      type: object
      description: >
        Response object returned for each recipient when sending an email.

        Contains the message ID for tracking and any error information if the
        submission failed.
      properties:
        to:
          type: string
          description: The recipient email address this response corresponds to
          example: customer@example.com
        submittedAt:
          type: integer
          format: int64
          description: >
            UNIX epoch timestamp in nanoseconds when the email was accepted for
            processing.

            Use this for precise timing and correlation with webhook events.
          example: 1704067200000000000
        messageId:
          type: string
          description: >
            Unique identifier (UUID) for this email message.

            Use this ID to track the email through webhooks and the message
            lookup API.
          example: 550e8400-e29b-41d4-a716-446655440000
        errorCode:
          type: integer
          description: |
            Error code if the email submission failed:
            - 0: Success (no error)
            - 1: Invalid recipient email
            - 2: Recipient in suppression list
            - 3: `from` domain doesn't exist in this sub-account
            - 4: `from` domain isn't verified
            - 5: IP pool doesn't exist
            - 6: Template doesn't exist
            - 7: Empty template name
            - 8: Internal error (message ID generation)
            - 9: Internal error (message storage)
            - 10: Invalid attachment
            - 11: Invalid `tpspFrom`
          example: 0
        message:
          type: string
          description: |
            Human-readable message describing the result.
            On success: "Email submitted successfully"
            On error: Description of what went wrong
          example: Email submitted successfully
      example:
        to: customer@example.com
        submittedAt: 1704067200000000000
        messageId: 550e8400-e29b-41d4-a716-446655440000
        errorCode: 0
        message: Email submitted successfully
    EmailAddress:
      type: object
      description: An email address with an optional display name
      required:
        - email
      properties:
        email:
          type: string
          format: email
          description: The email address (must be a valid email format)
          example: sender@example.com
        name:
          type: string
          description: |
            Display name shown in email clients.
            Will appear as "Name <email@example.com>" in the From/To fields.
          example: John Doe
          maxLength: 256
      example:
        email: sender@example.com
        name: John Doe
    Recipient:
      type: object
      description: >
        A recipient of the email with optional CC, BCC, and custom fields for
        personalization.

        Each recipient receives their own copy of the email with their specific
        custom field values.
      required:
        - email
      properties:
        email:
          type: string
          format: email
          description: The recipient's email address
          example: recipient@example.com
        name:
          type: string
          description: The recipient's display name
          example: Jane Smith
          maxLength: 256
        cc:
          type: array
          description: |
            Carbon copy recipients for this specific recipient's email.
            CC addresses will be visible to all recipients of this email copy.
          items:
            $ref: '#/components/schemas/CopyTo'
          maxItems: 50
        bcc:
          type: array
          description: |
            Blind carbon copy recipients for this specific recipient's email.
            BCC addresses are hidden from all other recipients.
          items:
            $ref: '#/components/schemas/CopyTo'
          maxItems: 50
        customFields:
          type: object
          additionalProperties: true
          description: >
            Custom fields for personalizing the email content for this
            recipient.

            Use Handlebars syntax ({{fieldName}}) in subject, htmlBody, or
            textBody to insert values.

            Reserved field names: `unsubscribe` (auto-generated unsubscribe
            link).
          example:
            firstName: Jane
            lastName: Smith
            accountId: ACC-12345
            planName: Premium
      example:
        email: jane@example.com
        name: Jane Smith
        cc:
          - email: manager@example.com
            name: Manager
        customFields:
          firstName: Jane
          companyName: Acme Corp
    Attachment:
      type: object
      description: >
        A file attachment for the email.

        The content must be Base64 encoded. Maximum total attachment size per
        email is 25MB.
      required:
        - content
        - filename
      properties:
        content:
          type: string
          format: byte
          description: |
            Base64 encoded content of the attachment file.
            Ensure proper encoding to avoid corruption.
          example: SGVsbG8gV29ybGQh
        filename:
          type: string
          description: |
            Name of the attachment file as it will appear to recipients.
            Include the file extension (e.g., "report.pdf", "image.png").
          example: invoice-12345.pdf
          maxLength: 255
      example:
        filename: monthly-report.pdf
        content: JVBERi0xLjQKJeLjz9MKMyAwIG9...
    CopyTo:
      type: object
      description: A CC or BCC recipient with optional custom fields
      required:
        - email
      properties:
        email:
          type: string
          format: email
          description: The CC/BCC recipient's email address
          example: cc@example.com
        name:
          type: string
          description: The CC/BCC recipient's display name
          example: Copy Recipient
          maxLength: 256
        customFields:
          type: object
          additionalProperties: true
          description: |
            Custom fields specific to this CC/BCC recipient.
            Allows personalization in CC/BCC copies of the email.
          example:
            role: Manager
      example:
        email: cc@example.com
        name: Copy Recipient
  securitySchemes:
    subAccountAuth:
      type: apiKey
      in: header
      name: X-SubAccount-ApiKey
      description: This api key can be used only for sub account level operations

````

This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.