Email

Send one email per request from a mailbox on your verified sending domain. You can write the email yourself or merge a saved template with a contact. To email a whole list, use an email campaign.

A 202 means accepted, not delivered. Delivery, opens, clicks, bounces and complaints arrive on the contact.email.status webhook. Calling hours, the contact frequency limit and retries are explained in Send lifecycle. What each reason_code means, and what to do about it, is in Outcomes and what to do.

Routes

Method Route Scope What it does
POST /email/public/email email:send Send an email you wrote
POST /email/public/email/merged-template email:send Merge a saved template with a contact and send it
GET /email/public/email contacts:read List sent and received emails
GET /domain/public/mailboxes email:read List the mailboxes you can send from

Before you send

  • Set up a sending domain. Verify a domain and create a mailbox on it in the dashboard. Without one, sends answer success: false.
  • Pick the send type. transactional, the default, is for receipts, reminders and replies. bulk is for marketing: it adds unsubscribe handling and uses the bulk frequency limit. A sending domain set to one purpose overrides what you pass.
  • Follow CAN-SPAM for marketing. Use an accurate sender and subject, include your postal address and a working unsubscribe, and don't email people who opted out.

Send an email

POST /email/public/email sends the subject and HTML you supply.

Field Type Required Description
to object[] One of to or contact_id Recipients as { "address", "name" }. An address with no contact creates one.
contact_id string One of to or contact_id Send to the contact's primary email.
mailbox_id string One of mailbox_id or from The mailbox to send from. Use this when you can.
from object[] One of mailbox_id or from One { "address", "name" } on a verified domain
subject string Yes Subject line
html string Yes HTML body
text string No Plain-text version
preview string No Preview text that most inboxes show after the subject
cc, bcc object[] No More recipients as { "address", "name" }
send_type string No transactional (default) or bulk
template_id string No Records which template this email came from. Nothing is merged.
curl -X POST https://api-v2.dropcowboy.com/email/public/email \
  -H "x-key: $DC_KEY" -H "x-secret: $DC_SECRET" \
  -H "Idempotency-Key: 2f9b4d7e-1a3c-4e6b-8d2f-5c7a9e1b3d64" \
  -H "Content-Type: application/json" \
  -d '{
    "to": [{ "address": "jordan.rivera@example.com", "name": "Jordan Rivera" }],
    "mailbox_id": "c5f1a8d3-6e2b-4c9f-b1a7-8d4e2c6f9b35",
    "subject": "Your order is ready",
    "html": "<p>Hi Jordan, your order is ready for pickup.</p>"
  }'
{
  "data": { "success": true },
  "meta": { "request_id": "c2a6e8f4-3b9d-4c1e-8a7f-5d3b1e9c6a24" }
}

Check success

A well-formed request answers 200 even when nothing was sent, so always read data.success. When it's false, data.error says why, for example that the account has no sending domain. Fix the cause before you retry.

Send an Idempotency-Key header so a retry can't send twice. This route is the only email route that accepts one. See Retry safely with Idempotency-Key.

Merge a saved template

POST /email/public/email/merged-template fills a saved email template from the recipient contact and sends it.

Field Type Required Description
template_id string Yes An email template. Find yours with GET /template/public/templates?type=email.
contact_id string One of contact_id or to The contact whose fields fill the template
to object[] One of contact_id or to A recipient address. A contact is created if none matches.
mailbox_id string One of mailbox_id or from The mailbox to send from
from object[] One of mailbox_id or from One { "address", "name" } on a verified domain
subject_override string No Use this subject instead of the template's
merged_user_id string No The user whose details fill the template's sender fields, as the user_id from GET /user/public/users. Defaults to the key's user.
preview string No Preview text
cc, bcc object[] No More recipients
send_type string No transactional (default) or bulk
curl -X POST https://api-v2.dropcowboy.com/email/public/email/merged-template \
  -H "x-key: $DC_KEY" -H "x-secret: $DC_SECRET" \
  -H "Content-Type: application/json" \
  -d '{
    "template_id": "f8a2c6e4-1d9b-4f3a-8c5e-7b1d3f9a2c46",
    "contact_id": "5a4b3c2d-1e0f-4a9b-8c7d-6e5f4a3b2c1d",
    "mailbox_id": "c5f1a8d3-6e2b-4c9f-b1a7-8d4e2c6f9b35",
    "send_type": "bulk"
  }'

The response is the same as Send an email: read data.success. A template that doesn't exist answers 404. RCS templates are refused.

List emails

GET /email/public/email returns sent and received emails, newest first.

Field Type Required Description
contact_id string No Only this contact's emails
direction string No inbound or outbound
skip integer No How many to skip. Default 0.
limit integer No How many to return. Default 50.
include_total boolean No Also return total
curl "https://api-v2.dropcowboy.com/email/public/email?contact_id=5a4b3c2d-1e0f-4a9b-8c7d-6e5f4a3b2c1d&limit=10" \
  -H "x-key: $DC_KEY" -H "x-secret: $DC_SECRET"
{
  "data": {
    "emails": [
      {
        "email_id": "7a3e9c1f-5d2b-4f8a-9e6c-1b4d7f3a8c52",
        "contact_id": "5a4b3c2d-1e0f-4a9b-8c7d-6e5f4a3b2c1d",
        "mailbox_id": "c5f1a8d3-6e2b-4c9f-b1a7-8d4e2c6f9b35",
        "template_id": null,
        "direction": "outbound",
        "send_type": "transactional",
        "to": [{ "address": "jordan.rivera@example.com", "name": "Jordan Rivera" }],
        "from": [{ "address": "hello@mail.example.com", "name": "Example Store" }],
        "subject": "Your order is ready",
        "created_at": 1774041600000,
        "sent_at": 1774041602000
      }
    ],
    "total": 1
  },
  "meta": { "request_id": "c2a6e8f4-3b9d-4c1e-8a7f-5d3b1e9c6a24" }
}

Timestamps are epoch milliseconds. An email that a sending rule stopped has state: "blocked" and a blocked_reason, such as too_many_bulk_emails.

List your mailboxes

GET /domain/public/mailboxes lists the mailboxes you can send from. Pass a mailbox_id to the send routes, or as email_from_mailbox_id on an email campaign.

curl https://api-v2.dropcowboy.com/domain/public/mailboxes \
  -H "x-key: $DC_KEY" -H "x-secret: $DC_SECRET"
{
  "data": {
    "mailboxes": [
      {
        "mailbox_id": "c5f1a8d3-6e2b-4c9f-b1a7-8d4e2c6f9b35",
        "title": "Hello",
        "address": "hello@mail.example.com",
        "domain": "mail.example.com",
        "display_name": "Example Dental",
        "is_personal": false
      }
    ]
  },
  "meta": { "request_id": "c2a6e8f4-3b9d-4c1e-8a7f-5d3b1e9c6a24" }
}

Results

Delivery, opens, clicks, bounces and complaints arrive on the contact.email.status webhook. It can fire several times for one email. status is delivered, opened, clicked, bounced or complained. delivered fires once, when the receiving mail server accepts the email. An email blocked before sending gets a single event with status: failure and the reason_code that blocked it.

{
  "event": "contact.email.status",
  "data": {
    "email_id": "7a3e9c1f-5d2b-4f8a-9e6c-1b4d7f3a8c52",
    "contact_id": "5a4b3c2d-1e0f-4a9b-8c7d-6e5f4a3b2c1d",
    "to": "jordan.rivera@example.com",
    "from": "hello@mail.example.com",
    "status": "bounced",
    "reason": "hard_bounce",
    "reason_code": 5030
  }
}

If you keep your own suppression list, also subscribe to contact.email.bounce_hard and contact.email.complaint. Email codes are the 5xxx rows in Outcomes. See Webhooks to subscribe.

Email frequency limit

Email has its own per-contact limit, separate from the phone contact frequency limit. By default a contact can get 15 bulk emails in 3 days and 30 transactional emails in 24 hours. Both can be changed for your account. An email over the limit is blocked with too_many_bulk_emails (5019) or too_many_transactional_emails (5020); send it later.

Addresses on your email test list, on the Dialing rules page, skip the limit, so you can send yourself test mail as often as you like.

Errors

Status Cause What to do
400 The request is malformed Fix the fields.
402 The account is past due Update billing; see Payment required.
403 The key lacks the scope, or your plan doesn't include email Add the scope, or add email to your plan. The body is {"error", "message", "feature"}.
404 The template doesn't exist (merged template only) Check template_id.
429 Too many requests Back off and retry.

For everything else, see Responses, errors and limits.

Common problems

  • success is false. Read data.error. Most often the account has no verified sending domain or mailbox.
  • The email shows state: "blocked". Check blocked_reason. For too_many_bulk_emails or too_many_transactional_emails, the contact hit the frequency limit; send later.
  • Merge fields came out empty. The recipient didn't match a contact with those fields filled in. Send contact_id with Merge a saved template.
  • The email bounced (5030). The address won't accept mail. Stop emailing it.

For more symptoms and fixes, see Troubleshooting.


While Drop Cowboy provides tools to support compliance efforts, customers remain solely responsible for obtaining proper consent, maintaining opt-out lists, and complying with all federal and state telemarketing regulations. Consult with your legal counsel to ensure your specific use case and consent mechanisms comply with applicable laws.

Code samples

The requests from this page, ready to copy. Set DC_KEY and DC_SECRET to your API key pair first.

Send an email
curl -X POST https://api-v2.dropcowboy.com/email/public/email \
  -H "x-key: $DC_KEY" -H "x-secret: $DC_SECRET" \
  -H "Idempotency-Key: 2f9b4d7e-1a3c-4e6b-8d2f-5c7a9e1b3d64" \
  -H "Content-Type: application/json" \
  -d '{
    "to": [{ "address": "jordan.rivera@example.com", "name": "Jordan Rivera" }],
    "mailbox_id": "c5f1a8d3-6e2b-4c9f-b1a7-8d4e2c6f9b35",
    "subject": "Your order is ready",
    "html": "<p>Hi Jordan, your order is ready for pickup.</p>"
  }'
Merge a saved template
curl -X POST https://api-v2.dropcowboy.com/email/public/email/merged-template \
  -H "x-key: $DC_KEY" -H "x-secret: $DC_SECRET" \
  -H "Content-Type: application/json" \
  -d '{
    "template_id": "f8a2c6e4-1d9b-4f3a-8c5e-7b1d3f9a2c46",
    "contact_id": "5a4b3c2d-1e0f-4a9b-8c7d-6e5f4a3b2c1d",
    "mailbox_id": "c5f1a8d3-6e2b-4c9f-b1a7-8d4e2c6f9b35",
    "send_type": "bulk"
  }'
List emails
curl "https://api-v2.dropcowboy.com/email/public/email?contact_id=5a4b3c2d-1e0f-4a9b-8c7d-6e5f4a3b2c1d&limit=10" \
  -H "x-key: $DC_KEY" -H "x-secret: $DC_SECRET"
List your mailboxes
curl https://api-v2.dropcowboy.com/domain/public/mailboxes \
  -H "x-key: $DC_KEY" -H "x-secret: $DC_SECRET"