---
title: "Create Email"
method: POST
path: "/emails"
tags: ["Emails"]
---

# Create Email

`POST /emails`

Create a new email

## Request body

- EmailInput
  - `attachments` string[] — A list of attachment IDs present on the email. (See [Attachments](https://docs.buttondown.com/api-attachments-introduction) for more information.)
  - `publish_date` string, date-time, nullable — The date and time at which the email should be published in the future (for scheduled emails), or the date and time at which the email was published (for sent emails).
  - `subject` string, required — The subject line for the email.
  - `slug` string, nullable — A short, human-readable identifier for the email, used in the archive URL.
  - `description` string — A human-readable description of the email, used for archives and SEO.
  - `canonical_url` string — The URL of the original source of the content.
  - `image` string — A primary image URL used when previewing the email on the web or in other contexts.
  - `body` string — The body of the email, in either HTML or markdown format. Buttondown attempts to intelligently detect the format of the body automatically, but you can also specify the format explicitly by prepending the text with the `buttondown-editor-mode` comment: `<!-- buttondown-editor-mode: fancy -->` or `<!-- buttondown-editor-mode: plaintext -->`.
  - `archival_mode` 'archive_only' | 'disabled' | 'enabled' | 'enabled_for_paid_subscribers' | 'enabled_for_subscribers' — Governs who can view this email in the archive. `ARCHIVE_ONLY` is the odd one out: the email is publicly archived but is not email content at all (e.g. an imported blog post), so it is excluded from email-rendering contexts like "recent issues" widgets.
  - `email_type` 'public' | 'private' | 'premium' | 'free' | 'churned' | 'archival' — The legacy single-axis representation of an email's audience and archive visibility. No longer stored: `filters` owns the audience axis and `archival_mode` owns the archive axis, and the deprecated API field is derived from those (see `email_type` below).
  - `status` 'draft' | 'managed_by_rss' | 'about_to_send' | 'scheduled' | 'in_flight' | 'paused' | 'deleted' | 'errored' | 'sent' | 'imported' | 'throttled' | 'resending' | 'transactional' | 'suppressed' — Represents the state of an email. No action is required to move from one state or another; Buttondown internally handles the transitions, and exposing the status is for observability purposes only.
  - `metadata` object — A structured key-value blob that you can use to store arbitrary data on the object. Metadata can be nested — you can store objects and arrays within your metadata. (You can [read more about metadata.](https://docs.buttondown.com/metadata))
  - `secondary_id` integer, nullable — An informal 'number' for the email, used in some templates (e.g. 'This was issue #123').
  - `filters` EmailFilterGroup
    - `filters` EmailFilter[], required — The leaf-level filters to apply to the audience.
      - `field` union, required — The subscriber attribute to evaluate. Must be a recognized field or a `subscriber.metadata.*` path.
        - 'subscriber.churn_date' | 'subscriber.click_rate' | 'subscriber.last_click_date' | 'subscriber.last_open_date' | 'subscriber.open_rate' | 'subscriber.price' | 'subscriber.source' | 'subscriber.status' | 'subscriber.subscription_date' | 'subscriber.tags' | 'subscriber.upgrade_date'
        - string
      - `operator` 'equals' | 'not_equals' | 'contains' | 'not_contains' | 'is_empty' | 'is_not_empty' | 'greater_than' | 'less_than', required — An enumeration.
      - `value` string, required — The value to compare the field against.
    - `groups` EmailFilterGroup[], required — The nested groups to apply to the audience.
    - `predicate` 'and' | 'or', required — The logical operator to use when combining filters.
  - `template` 'classic' | 'custom' | 'modern' | 'plaintext' | 'naked' — Represents the template of an email. Each template has a different layout/style; you can view screenshots and examples [in the docs](https://docs.buttondown.com/customizing-email-design#buttondowns-default-templates).
  - `commenting_mode` 'disabled' | 'enabled' | 'enabled_for_paid_subscribers' — Governs who can comment on this email. This enum replaces the `is_comments_disabled` field, which has been deprecated. (Also note that this field may be superseded by newsletter-level settings; for instance, "enabled" is an invalid and inert value if the newsletter itself has comments disabled.)
  - `related_email_ids` string[] — IDs of emails related to this one. Shown at the bottom of the email and archive pages.
  - `featured` boolean — Designated whether or not this email should be highlighted within the archives.
  - `should_trigger_pay_per_email_billing` boolean — Whether this email should trigger pay-per-email billing for paid subscribers. Use this to differentiate between free updates and premium newsletters.

## Response `201`

Created

- Email — Emails are why you're here on Buttondown, right? Creating an email via the API is just like creating one in the interface; it will instantly trigger sending actual emails, based on the tags and email type you provide. Relevant changes to the schema: - [2024-08-15](https://docs.buttondown.com/api-changelog-2024-08-15): unshipped the `included_tags` and `excluded_tags` fields. - [2024-12-30](https://docs.buttondown.com/api-changelog-2024-12-30): unshipped the `is_comments_disabled` field, and replaced it with a more flexible `commenting_mode` field. - [2025-09-23](https://docs.buttondown.com/api-changelog-2025-09-23): increased the maximum length of the `subject` field from 1000 to 2000 characters.
  - `id` string, required — A unique TypeID associated with the object.
  - `creation_date` string, date-time, required — The date and time at which the object was first created.
  - `absolute_url` string, required — The canonical web URL of the email on the newsletter's archive.
  - `analytics` Analytics
    - `recipients` integer — The number of subscribers the email was dispatched to.
    - `deliveries` integer — The number of successful deliveries (recipients minus failures).
    - `opens` integer — The number of unique opens recorded.
    - `clicks` integer — The number of unique link clicks recorded.
    - `temporary_failures` integer — The number of temporary delivery failures (e.g. soft bounces).
    - `permanent_failures` integer — The number of permanent delivery failures (e.g. hard bounces).
    - `unsubscriptions` integer — The number of subscribers who unsubscribed after receiving this email.
    - `complaints` integer — The number of spam complaints recorded against this email.
    - `survey_responses` integer — The number of survey responses submitted from this email.
    - `webmentions` integer — The number of inbound webmentions received for this email.
    - `page_views_lifetime` integer — The total number of archive page views for this email since publication.
    - `page_views_30` integer — The number of archive page views in the last 30 days.
    - `page_views_7` integer — The number of archive page views in the last 7 days.
    - `subscriptions` integer — The number of new subscribers attributed to this email.
    - `paid_subscriptions` integer — The number of new paid subscribers attributed to this email.
    - `replies` integer — The number of reply emails received from subscribers.
    - `comments` integer — The number of comments posted on this email.
    - `social_mentions` integer — The number of social media mentions of this email.
    - `temporary_failure_breakdown` FailureBreakdownItem[] — Breakdown of temporary failures by reason code, sorted by count descending.
      - `code` string, required — The failure reason code (e.g. 'hard_bounce', 'spam')
      - `count` integer, required — Number of failures with this reason
    - `permanent_failure_breakdown` FailureBreakdownItem[] — Breakdown of permanent failures by reason code, sorted by count descending.
      - `code` string, required — The failure reason code (e.g. 'hard_bounce', 'spam')
      - `count` integer, required — Number of failures with this reason
  - `callouts` Callout[] — A list of callouts that apply to this email — surfaced in the UI alongside analytics to flag context the reader should know about (e.g., first send on a custom sending domain).
  - `attachments` string[], nullable — A list of attachment IDs present on the email. (See [Attachments](https://docs.buttondown.com/api-attachments-introduction) for more information.)
  - `body` string, required — The body of the email, in either HTML or markdown format. Buttondown attempts to intelligently detect the format of the body automatically, but you can also specify the format explicitly by prepending the text with the `buttondown-editor-mode` comment: `<!-- buttondown-editor-mode: fancy -->` or `<!-- buttondown-editor-mode: plaintext -->`.
  - `canonical_url` string, required — The URL of the original source of the content.
  - `commenting_mode` 'disabled' | 'enabled' | 'enabled_for_paid_subscribers', required — Governs who can comment on this email. This enum replaces the `is_comments_disabled` field, which has been deprecated. (Also note that this field may be superseded by newsletter-level settings; for instance, "enabled" is an invalid and inert value if the newsletter itself has comments disabled.)
  - `description` string, required — A human-readable description of the email, used for archives and SEO.
  - `archival_mode` 'archive_only' | 'disabled' | 'enabled' | 'enabled_for_paid_subscribers' | 'enabled_for_subscribers', required — Governs who can view this email in the archive. `ARCHIVE_ONLY` is the odd one out: the email is publicly archived but is not email content at all (e.g. an imported blog post), so it is excluded from email-rendering contexts like "recent issues" widgets.
  - `email_type` 'public' | 'private' | 'premium' | 'free' | 'churned' | 'archival' — The legacy single-axis representation of an email's audience and archive visibility. No longer stored: `filters` owns the audience axis and `archival_mode` owns the archive axis, and the deprecated API field is derived from those (see `email_type` below).
  - `featured` boolean, required — Designated whether or not this email should be highlighted within the archives.
  - `filters` FilterGroup, required — Buttondown's filtering schema can be used for multiple things: - Filtering [the audience of an email](/api-emails-create) to a specific subset - Creating [finely-tuned automations](/api-automation-introduction) Filters are fractal; they can be nested in groups, and groups can be nested in other groups. This is accomplished through a tree-like structure. Every "FilterGroup" has a "predicate" field, which is either "and" or "or", which determines how the filters and groups within the group are combined, a "groups" field, which is a list of "FilterGroup" objects (that's that recursive bit!), and a "filters" field, which are the leaf-level filters themselves. Let's say you want a simple filter: all subscribers who have a tag whose ID is `sub_tag_0j6hb7h40j6hb7h40j6hb7h40j`. You can do that like this: ```json { "filters": [{"field": "subscriber.tags", "operator": "contains", "value": "sub_tag_0j6hb7h40j6hb7h40j6hb7h40j"}], "groups": [], "predicate": "and" } ``` Now, let's say you want to filter for subscribers who have that tag and a tag whose ID is `sub_tag_0j6hb7h40j6hb7h40j6hb7h40k`. You can do that like this: ```json { "filters": [{"field": "subscriber.tags", "operator": "contains", "value": "sub_tag_0j6hb7h40j6hb7h40j6hb7h40j"}, {"field": "subscriber.tags", "operator": "contains", "value": "sub_tag_0j6hb7h40j6hb7h40j6hb7h40k"}], "groups": [], "predicate": "and" } ``` If you wanted to change that `and` to an `or`, you can do that like this: ```json { "filters": [{"field": "subscriber.tags", "operator": "contains", "value": "sub_tag_0j6hb7h40j6hb7h40j6hb7h40j"}, {"field": "subscriber.tags", "operator": "contains", "value": "sub_tag_0j6hb7h40j6hb7h40j6hb7h40k"}], "groups": [], "predicate": "or" } ``` Now, let's say you want to filter for subscribers who have the first tag _or_ both the second tag and a third tag whose ID is `sub_tag_0j6hb7h40j6hb7h40j6hb7h40m`. This is where the whole nested thing comes in handy. You can do that like this: ```json { "filters": [{"field": "subscriber.tags", "operator": "contains", "value": "sub_tag_0j6hb7h40j6hb7h40j6hb7h40j"}], "groups": [ { "filters": [{"field": "subscriber.tags", "operator": "contains", "value": "sub_tag_0j6hb7h40j6hb7h40j6hb7h40k"}, {"field": "subscriber.tags", "operator": "contains", "value": "sub_tag_0j6hb7h40j6hb7h40j6hb7h40m"}], "groups": [], "predicate": "and" } ], "predicate": "or" } ``` You can read more about the specific filter construction in the [Filter documentation](/api-emails-filter).
    - `filters` Filter[], required — The leaf-level filters to apply to the audience.
      - `field` string, required
      - `operator` 'equals' | 'not_equals' | 'contains' | 'not_contains' | 'is_empty' | 'is_not_empty' | 'greater_than' | 'less_than', required — An enumeration.
      - `value` string, required
    - `groups` FilterGroup[], required — The nested groups to apply to the audience.
    - `predicate` 'and' | 'or', required — The logical operator to use when combining filters (either 'and' or 'or').
  - `image` string, required — A primary image URL used when previewing the email on the web or in other contexts.
  - `metadata` object — A structured key-value blob that you can use to store arbitrary data on the object. Metadata can be nested — you can store objects and arrays within your metadata. (You can [read more about metadata.](https://docs.buttondown.com/metadata))
  - `modification_date` string, date-time, required — The date and time at which the object was last modified.
  - `publish_date` string, date-time, nullable — The date and time at which the email should be published in the future (for scheduled emails), or the date and time at which the email was published (for sent emails).
  - `related_email_ids` string[], required — A list of email IDs that are related to this email. Related emails are shown at the bottom of the email and archive pages.
  - `secondary_id` integer, nullable — An informal 'number' for the email, used in some templates ('This was issue #123').
  - `should_trigger_pay_per_email_billing` boolean, required — Whether this email should trigger pay-per-email billing for paid subscribers. Use this to differentiate between free updates and premium newsletters.
  - `slug` string, nullable — A short, human-readable identifier for the email, used in the archive URL.
  - `source` 'api' | 'import' | 'app' | 'external_feed' | 'smtp', required — Represents the original provenance of an email. This value is not exposed to subscribers, but does determine some behavior of the email (e.g. whether or not analytics can be calculated.)
  - `status` 'draft' | 'managed_by_rss' | 'about_to_send' | 'scheduled' | 'in_flight' | 'paused' | 'deleted' | 'errored' | 'sent' | 'imported' | 'throttled' | 'resending' | 'transactional' | 'suppressed', required — Represents the state of an email. No action is required to move from one state or another; Buttondown internally handles the transitions, and exposing the status is for observability purposes only.
  - `subject` string, required — The subject line for the email.
  - `suppression_reason` 'law_enforcement' | 'internal_auditing' — Represents the reason an email was suppressed.
  - `template` 'classic' | 'custom' | 'modern' | 'plaintext' | 'naked' — Represents the template of an email. Each template has a different layout/style; you can view screenshots and examples [in the docs](https://docs.buttondown.com/customizing-email-design#buttondowns-default-templates).

## Other responses

- `400` — Bad Request
- `401` — Unauthorized
- `403` — Forbidden
- `409` — Conflict
- `422` — Unprocessable Entity
- `429` — Too Many Requests

---

[API](https://skmtc.net/buttondown/apis/buttondown-api.md) · [All operations](https://skmtc.net/buttondown/apis/buttondown-api/llms.txt) · [OpenAPI document](https://skmtc-service-staging.skmtc.workers.dev/v1/apis/buttondown/buttondown-api/versions/3a702c095d22/schema)
