Create & Send emails

Learn how to send emails using Unipile API.

Email deliverability

In most cases, major email providers like Google, Microsoft, and IMAP providers automatically configure DKIM, SPF and eventually DMARC when users set up their internal email systems. If you're simply creating a system for email sync and manual sending from your app, you can bypass managing these settings. Just instruct users to connect their email, ensuring they experience the same delivery results as with Outlook or Gmail.

However, if your system involves outreach or automatic sending at higher volumes, it's advisable to verify the proper configuration of these parameters to ensure optimal deliverability at scale.

If your company domain sends more than 5000 emails daily to Google or Yahoo, you need to maintain an abuse complaint rate of 0.3% or lower, or all company emails will be blocked by Google.

❗️

Unipile is not meant to send transactional or marketing emails

Sending bulk marketing or high-volume transactional emails directly from Gmail, Outlook or your own SMTP server can lead to spam filtering, rate limits, or account suspension.

For reliable delivery, proper IP reputation, bounce handling, and compliance with email regulations, use a dedicated provider such as Mailgun, Postmark, or Resend.


Provider limitations

Google

Gmail and Google Workspace accounts have different sending capacities: Gmail allows up to 500 emails per day, while Workspace increases that limit to 2,000. In practice, though, it’s best to stay well below these official caps to avoid being flagged. For Gmail, sending 50–100 emails per day is recommended (up to 150 if your reputation is strong), while Workspace is safer around 100–150 per day (up to 300 with good engagement). For new accounts, always start slowly — around 20–50 emails per day — and increase gradually as your reputation builds.

Beyond volume, Gmail also enforces API quotas that apply across all actions. If you send too many requests at once, you’ll quickly run into 429 Too Many Requests errors, so you need to spread calls over time. See the Gmail API quota reference for details.

If you need more flexibility, Google Workspace lets you create multiple domains and link them as aliases to your main account. With Unipile’s API you can then list these aliases and use them as the from address, which allows you to distribute sending reputation across several domains while still managing everything from a single connected Gmail account. More details are available in Google’s documentation.


Outlook

For Microsoft 365 subscribers, sending limits are higher but still enforced. You can send email to up to 5,000 recipients per day, with a maximum of 500 recipients per single message. Within that total, no more than 1,000 can be “non-relationship recipients” — people you haven’t emailed before. These numbers may be lower for non-subscribers, and limits can also adjust depending on your account’s usage history. If you send mail through third-party connected accounts, the provider’s own limits will apply.

Beyond these official caps, it’s wise to follow the same best practices described in the Gmail section: keep your daily sending volumes conservative, grow gradually, and prioritize quality engagement to protect your deliverability.


Other providers

The limitations may vary depending on your email provider. Please refer to your users provider's documentation or inquire with them directly for specific details.

Apart from official recommendations, we advise respecting the "Recommended Sending Limits" in Gmail part


Build an email

For the following examples we'll use this built email:

const email = {
  to: [
    {
      display_name: 'John Doe',
      email: '[email protected]',
    },
  ],
  cc: [
    {
      display_name: 'Jane Doe',
      email: '[email protected]',
    },
  ],
  subject: 'Hello',
  plain_text: 'Hello, world!',
  html: '<p>Hello, world!</p>',
}
email = {
    "to": [
        {
            "display_name": "John Doe",
            "email": "[email protected]",
        }
    ],
    "cc": [
        {
            "display_name": "Jane Doe",
            "email": "[email protected]",
        }
    ],
    "subject": "Hello",
    "plain_text": "Hello, world!",
    "html": "<p>Hello, world!</p>",
}

We recommend to set a plain text even if your email contains HTML as it is used by clients to display a snippet of the email in Inboxes.


Send from a draft

A draft is a saved email that is not ready to be sent.

To create a new draft, use the Create a Draft method. This will create a new email in the Drafts mailbox.

const { data } = await emailsApi.createDraft({
  path: {
    account_id: "acc_123456789",
  },
  body: email,
});

const draft_id = data.id;
draft = emails_api.create_draft("acc_123456789", email)
draft_id = draft.id
curl --request POST \
     --url https://api.unipile.com/v2/account_id/drafts \
     --header 'accept: application/json' \
     --header 'content-type: application/json' \
     --data '
{
  "html": "<p>Hello, world!</p>",
  "plain_text": "Hello, world!",
  "subject": "Hello",
  "to": [
    {
      "email": "[email protected]",
      "display_name": "John Doe"
    }
  ],
  "cc": [
    {
      "display_name": "Jane Doe",
      "email": "[email protected]"
    }
  ]
}
'

Then, you can edit the draft using Update a Draft.

Once the Draft is ready to be sent, use the Send a Draft method and provide the ID of the Draft.

In this exemple, we use the draft_id from the response of Create a Draft, but you can get IDs by using List all Drafts.

await emailsApi.sendDraft({
  path: {
    account_id: "acc_123456789",
    draft_id,
  },
});
emails_api.send_draft("acc_123456789", draft_id)
curl --request POST \
     --url https://api.unipile.com/v2/account_id/drafts/draft_id/send \
     --header 'accept: application/json'

Send directly

To send an email from the linked account, use Send an Email method and provide the email content.

await emailsApi.sendEmail({
  path: {
    account_id: "acc_123456789",
  },
  body: email,
});
emails_api.send_email("acc_123456789", email)
curl --request POST \
     --url https://api.unipile.com/v2/account_id/emails/send \
     --header 'accept: application/json' \
     --header 'content-type: application/json' \
     --data '
{
  "to": [
    {
      "display_name": "John Doe",
      "email": "[email protected]"
    }
  ],
  "subject": "Hello",
  "plain_text": "Hello, world!",
  "html": "<p>Hello, world!</p>"
}
'

Send attachments

To send attachments, include files in the attachments array.

The content of the file must be encoded to base64.

const file = await readFile('document.pdf');

await emailsApi.sendEmail({
  path: {
    account_id: "acc_123456789",
  },
  body: {
    ...email,
    attachments: [
      {
        content: file.toString('base64'),
        content_type: 'application/pdf',
        filename: 'document.pdf',
      },
    ],
  },
});
import base64

with open("document.pdf", "rb") as f:
    content = base64.b64encode(f.read()).decode("utf-8")

emails_api.send_email(
    "acc_123456789",
    {
        **email,
        "attachments": [
            {
                "content": content,
                "content_type": "application/pdf",
                "filename": "document.pdf",
            }
        ],
    },
)
curl --request POST \
     --url https://api.unipile.com/v2/account_id/emails/send \
     --header 'accept: application/json' \
     --header 'content-type: application/json' \
     --data '
{
  "to": [
    {
      "display_name": "John Doe",
      "email": "[email protected]"
    }
  ],
  "subject": "PDF",
  "attachments": [
    {
      "content": "$(base64 -b 0 -i document.pdf)",
      "content_type": "application/pdf",
      "filename": "document.pdf",
    }
  ]
}
'
❗️

Provider limitations

Be aware of size and format limitations when sending files. We recommend to limit the size of an email to be under 25MB (including html