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

# Create or send an email message

> Queues, schedules, or sandbox-sends an email message. The legacy `/v2/emails` POST route
is a backward-compatible alias for this operation.

`subject` is required unless `template_id` is supplied. When using `template_id`, do not
also provide `subject`, `html_body`, or `text_body`; the template is rendered with
`template_variables`.

Note: template lookup failures (not found, wrong account) return 400, not 404.



## OpenAPI

````yaml /openapi/generated/email/messages.yml post /email_messages
openapi: 3.1.0
info:
  contact:
    email: support@telnyx.com
  description: API for sending and retrieving email messages.
  title: Telnyx Email Messages API
  version: 2.0.0
servers:
  - url: https://api.telnyx.com/v2
security:
  - bearerAuth: []
paths:
  /email_messages:
    post:
      tags:
        - Email Messages
      summary: Create or send an email message
      description: >-
        Queues, schedules, or sandbox-sends an email message. The legacy
        `/v2/emails` POST route

        is a backward-compatible alias for this operation.


        `subject` is required unless `template_id` is supplied. When using
        `template_id`, do not

        also provide `subject`, `html_body`, or `text_body`; the template is
        rendered with

        `template_variables`.


        Note: template lookup failures (not found, wrong account) return 400,
        not 404.
      operationId: CreateEmailMessage
      parameters:
        - $ref: '#/components/parameters/IdempotencyKey'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateEmailRequest'
            examples:
              simple:
                value:
                  from: sender@example.com
                  to:
                    - recipient@example.com
                  subject: Hello from Telnyx
                  text_body: This is a test email.
              withAddressObjects:
                value:
                  from:
                    email: sender@example.com
                    name: Telnyx Notifications
                  to:
                    - email: recipient@example.com
                      name: Ada Lovelace
                  subject: Welcome
                  html_body: <h1>Welcome!</h1>
              withTemplate:
                value:
                  from: sender@example.com
                  to:
                    - recipient@example.com
                  template_id: 7a7c1a2b-1111-4c72-8c21-2bbf3d40c123
                  template_variables:
                    first_name: Ada
      responses:
        '202':
          description: Message queued, scheduled, or sandbox-created.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/EmailMessageResponse'
          headers:
            Idempotent-Replayed:
              $ref: '#/components/headers/IdempotentReplayed'
            X-Telnyx-Reputation-Warning:
              description: >-
                Present with `warn` when the accepted send uses a sender domain
                in the reputation warn band; delivery proceeds with reduced
                sending limits.
              schema:
                type: string
                enum:
                  - warn
        '400':
          description: >-
            Bad Request / Validation Failed (10015). Invalid, duplicate, empty,
            malformed, or overlong Idempotency-Key headers are rejected by Edge
            with HTTP 400 and error code 10015.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/email_ErrorResponse'
              example:
                errors:
                  - code: '10015'
                    title: Bad Request
                    detail: email is required
        '401':
          $ref: '#/components/responses/email_UnauthorizedResponse'
        '403':
          $ref: '#/components/responses/email_ForbiddenResponse'
        '404':
          $ref: '#/components/responses/email_NotFoundResponse'
        '409':
          $ref: '#/components/responses/IdempotencyConflictResponse'
        '413':
          $ref: '#/components/responses/PayloadTooLargeResponse'
        '422':
          description: >-
            Validation failed, send-time template rendering failed, or all
            recipients suppressed (code `recipient_suppressed`, includes
            top-level `suppressed` array). Reusing an Idempotency-Key with a
            different request also returns 422 (10027).
          content:
            application/json:
              schema:
                oneOf:
                  - $ref: '#/components/schemas/email_ErrorResponse'
                  - $ref: '#/components/schemas/RenderErrorResponse'
                  - $ref: '#/components/schemas/RecipientSuppressedError'
        '429':
          description: Sending suspended — domain reputation band is 'poor'.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ReputationSuspendedError'
        '503':
          $ref: '#/components/responses/email_ServiceUnavailableResponse'
      x-codeSamples:
        - lang: JavaScript
          source: |-
            import Telnyx from 'telnyx';

            const client = new Telnyx({
              apiKey: process.env['TELNYX_API_KEY'], // This is the default and can be omitted
            });

            const EmailMessage = await client.emailMessages.create({
              from: 'from',
              to: 'to',
            });

            console.log(EmailMessage.data);
        - lang: Python
          source: |-
            import os
            from telnyx import Telnyx

            client = Telnyx(
                api_key=os.environ.get("TELNYX_API_KEY"),  # This is the default and can be omitted
            )
            email_message = client.email_messages.create(
                from_="from",
                to="to",
            )
            print(email_message.data)
        - lang: Go
          source: "package main\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\t\"github.com/team-telnyx/telnyx-go\"\n\t\"github.com/team-telnyx/telnyx-go/option\"\n)\n\nfunc main() {\n\tclient := telnyx.NewClient(\n\t\toption.WithAPIKey(\"My API Key\"),\n\t)\n\temailMessage, err := client.EmailMessages.New(\n\t\tcontext.TODO(),\n\t\ttelnyx.EmailMessageNewParams{\n\t\t\tFrom: \"from\",\n\t\t\tTo:   \"to\",\n\t\t},\n\t)\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf(\"%+v\\n\", emailMessage.Data)\n}\n"
        - lang: Java
          source: |-
            package com.telnyx.sdk.example;

            import com.telnyx.sdk.client.TelnyxClient;
            import com.telnyx.sdk.client.okhttp.TelnyxOkHttpClient;
            import com.telnyx.sdk.models.emailMessages.EmailMessageCreateParams;

            public final class Main {
                private Main() {}

                public static void main(String[] args) {
                    TelnyxClient client = TelnyxOkHttpClient.fromEnv();

                    EmailMessageCreateParams params = EmailMessageCreateParams.builder()
                        .from("from")
                        .to("to")
                        .build();
                    var response = client.emailMessages().create(params);
                }
            }
        - lang: Ruby
          source: |-
            require "telnyx"

            telnyx = Telnyx::Client.new(api_key: "My API Key")

            email_message = telnyx.email_messages.create(from: "from", to: "to")

            puts(email_message)
        - lang: PHP
          source: >-
            <?php


            require_once dirname(__DIR__) . '/vendor/autoload.php';


            use Telnyx\Client;

            use Telnyx\Core\Exceptions\APIException;


            $client = new Client(apiKey: getenv('TELNYX_API_KEY') ?: 'My API
            Key');


            try {
              $email_message = $client->emailMessages->create(
                from: 'from',
                to: 'to',
              );

              var_dump($email_message);
            } catch (APIException $e) {
              echo $e->getMessage();
            }
        - lang: CLI
          source: |-
            telnyx email-messages create \
              --api-key 'My API Key' \
              --from from \
              --to to
components:
  parameters:
    IdempotencyKey:
      name: Idempotency-Key
      in: header
      required: false
      description: >-
        Optional opaque, unquoted key for safely retrying the same logical
        request. Keys must contain 1 to 255 letters, numbers, hyphens, or
        underscores. Generate a unique UUID v4 for each operation and reuse it
        only when retrying that operation with the same request. Invalid
        headers—including duplicate, empty, malformed, or overlong values—return
        400 with error code 10015. A request already in progress with the same
        key returns 409; reusing the key with a different request returns 422.
        Only successful responses are replayed, for up to 24 hours. Do not
        include sensitive data in the key.
      schema:
        type: string
        minLength: 1
        maxLength: 255
        pattern: ^[A-Za-z0-9_-]{1,255}$
      example: 8e03978e-40d5-43e8-bc93-6894a57f9326
  schemas:
    CreateEmailRequest:
      type: object
      description: >-
        Recipient email addresses must be unique across `to`, `cc`, and `bcc`
        after case-insensitive normalization. Duplicate recipients return `400
        Bad Request`.
      properties:
        from:
          $ref: '#/components/schemas/EmailAddressInput'
        from_name:
          type: string
          description: >-
            Optional display name for string `from`; overrides `from.name` when
            provided.
        to:
          $ref: '#/components/schemas/EmailAddressArrayInput'
        cc:
          type: array
          items:
            $ref: '#/components/schemas/EmailAddressInput'
        bcc:
          type: array
          items:
            $ref: '#/components/schemas/EmailAddressInput'
        reply_to:
          $ref: '#/components/schemas/EmailAddressInput'
          description: >-
            Reply-to address. If provided as an object with a name, only the
            email is stored; the name is ignored.
        subject:
          type: string
          description: >-
            Required unless `template_id` is supplied. When using a template,
            the template's subject is rendered; if the template has no subject
            or renders empty, the request returns 400.
        html_body:
          type: string
          description: >-
            HTML email body. Returned only by `GET /email_messages/{id}`;
            omitted from create and list responses.
        text_body:
          type: string
          description: >-
            Plain text email body. Returned only by `GET /email_messages/{id}`;
            omitted from create and list responses.
        headers:
          type: object
          additionalProperties:
            type: string
          description: Custom email headers. Write-only; not returned in responses.
        attachments:
          type: array
          items:
            $ref: '#/components/schemas/AttachmentRequest'
        tags:
          type: array
          items:
            type: string
          description: >-
            Tags for categorization and reporting. Stored on the message and
            propagated to Email Detail Records. Not returned in API responses.
        group_id:
          type:
            - string
            - 'null'
          format: uuid
          description: >-
            Optional unsubscribe-group UUID used for group-scoped suppression
            checks and unsubscribe handling.
        ignore_suppression:
          type: boolean
          default: false
          description: >
            When true, allows delivery to recipients whose suppressions
            explicitly

            permit an override. Hard bounces, spam complaints, and
            invalid-address

            suppressions cannot be overridden. Requires the `email:override` API
            scope.
        metadata:
          type: object
          additionalProperties: true
          description: Custom metadata. Write-only; not returned in responses.
        tracking_settings:
          $ref: '#/components/schemas/TrackingSettings'
        template_id:
          type: string
          format: uuid
        template_variables:
          type: object
          default: {}
          additionalProperties: true
          description: >-
            Variables for Liquid template rendering. Non-object values may cause
            a 422 validation error on message creation, but are silently treated
            as an empty object for template rendering.
        scheduled_at:
          type:
            - string
            - 'null'
          format: date-time
          description: |
            Future ISO 8601 time to schedule sending. Invalid or past timestamps
            are silently ignored and the email is sent immediately. The legacy
            alias `send_at` is still accepted for backward compatibility; when
            both are provided, `scheduled_at` wins.
        send_at:
          type: string
          format: date-time
          deprecated: true
          description: Deprecated alias for `scheduled_at`.
        inline_css:
          type: boolean
          default: false
        sandbox_mode:
          type: boolean
          default: false
        in_reply_to_message_id:
          type:
            - string
            - 'null'
          format: uuid
          description: >-
            Telnyx message UUID of the message this send replies to. When
            provided,

            the API sets RFC 5322 `In-Reply-To` and `References` headers on the

            outbound MIME so the recipient's mailbox (Gmail/Outlook) threads it

            correctly. The parent is looked up under the caller's account scope;

            a UUID belonging to another account yields a non-enumerating 404.


            Wire-only (Phase 1): the API sets the headers and does NOT resolve
            or

            mutate `thread_id` on the server side. Messages sent without this

            parameter are standalone (no threading headers injected).


            Cannot be combined with `forward_of_message_id` (422).
        reply_to_all:
          type:
            - boolean
            - 'null'
          default: false
          description: |-
            Indicates a reply-all intent. In Phase 1 (wire-only) this does not
            change the threading headers — recipient selection is customer-
            controlled (`to`/`cc`), and a thread is not defined by its audience.
            When the referenced message has no thread context, reply-all
            degrades to a plain reply (parent ID only in `References`). The
            resolution engine (separate work) will expand the ancestor chain
            at a later phase with no API change.

            Only meaningful alongside `in_reply_to_message_id`.
        forward_of_message_id:
          type:
            - string
            - 'null'
          format: uuid
          description: |-
            Telnyx message UUID of the message this send forwards. Forwarded
            messages start a NEW thread per RFC 5322 — NO `In-Reply-To` or
            `References` headers are set on the outbound MIME. The id is
            recorded in the message's metadata for EDR provenance only.

            The id is validated as a UUID but is NOT looked up against the
            message store — existence is the caller's responsibility (the
            forward is pure metadata; it does not affect delivery). Cannot be
            combined with `in_reply_to_message_id` (422).
      required:
        - from
        - to
    EmailMessageResponse:
      type: object
      properties:
        data:
          $ref: '#/components/schemas/EmailMessage'
        suppressed:
          type: array
          description: >-
            Recipients removed by suppression checks when at least one recipient
            remains and the message is accepted.
          items:
            $ref: '#/components/schemas/SuppressedRecipient'
      required:
        - data
    email_ErrorResponse:
      type: object
      properties:
        errors:
          type: array
          items:
            $ref: '#/components/schemas/ErrorObject'
        suppressed:
          type: array
          description: >-
            Present when every recipient is suppressed, so the request is
            rejected and no message is created.
          items:
            $ref: '#/components/schemas/SuppressedRecipient'
      required:
        - errors
    RenderErrorResponse:
      type: object
      properties:
        errors:
          type: array
          items:
            $ref: '#/components/schemas/RenderErrorObject'
      required:
        - errors
    RecipientSuppressedError:
      type: object
      description: >-
        Non-standard error envelope returned when all recipients are suppressed
        and ignore_suppression was not set/allowed. Includes a top-level
        `suppressed` array alongside `errors`.
      properties:
        errors:
          type: array
          items:
            type: object
            properties:
              code:
                type: string
                enum:
                  - recipient_suppressed
              title:
                type: string
              detail:
                type: string
        suppressed:
          type: array
          items:
            type: object
            properties:
              to:
                type: string
                format: email
              reason:
                type: string
              scope:
                type: string
              override_allowed:
                type: boolean
    ReputationSuspendedError:
      type: object
      description: >-
        Non-standard error envelope returned when the sending domain's
        reputation band is 'poor'. Uses string code `reputation_suspended`
        instead of a numeric code.
      properties:
        errors:
          type: array
          items:
            type: object
            properties:
              code:
                type: string
                enum:
                  - reputation_suspended
              title:
                type: string
                example: Sending Suspended
              detail:
                type: string
    EmailAddressInput:
      oneOf:
        - type: string
        - $ref: '#/components/schemas/EmailAddress'
    EmailAddressArrayInput:
      type: array
      minItems: 1
      items:
        $ref: '#/components/schemas/EmailAddressInput'
    AttachmentRequest:
      type: object
      properties:
        filename:
          type: string
          description: Attachment filename. Defaults to "attachment" when omitted.
        content_type:
          type: string
          description: >-
            MIME content type. Defaults to "application/octet-stream" when
            omitted.
        content:
          type: string
          description: >-
            Attachment content, typically Base64-encoded. Defaults to empty
            string when omitted.
        disposition:
          type: string
          default: attachment
          description: MIME disposition (`attachment` or `inline`).
        content_id:
          type:
            - string
            - 'null'
          description: MIME Content-ID used to reference an inline attachment.
    TrackingSettings:
      type: object
      description: >-
        Per-send open and click tracking overrides. Omitted properties inherit
        the sender domain's tracking settings.
      properties:
        open_tracking:
          type: boolean
          description: Whether to inject an open-tracking pixel for this message.
        click_tracking:
          type: boolean
          description: Whether to rewrite links for click tracking in this message.
    EmailMessage:
      type: object
      properties:
        record_type:
          type: string
          enum:
            - email_message
        id:
          type: string
          format: uuid
        status:
          $ref: '#/components/schemas/EmailMessageStatus'
        from:
          $ref: '#/components/schemas/EmailAddress'
        to:
          type: array
          items:
            $ref: '#/components/schemas/EmailAddress'
        cc:
          type: array
          items:
            $ref: '#/components/schemas/EmailAddress'
        bcc:
          type: array
          items:
            $ref: '#/components/schemas/EmailAddress'
        reply_to:
          type:
            - string
            - 'null'
        subject:
          type: string
        template_id:
          type:
            - string
            - 'null'
          format: uuid
        template_variables:
          type: object
          additionalProperties: true
          default: {}
        attachments:
          type: array
          items:
            $ref: '#/components/schemas/AttachmentResponse'
        events:
          type: array
          items:
            $ref: '#/components/schemas/MessageEvent'
        created_at:
          type: string
          format: date-time
        scheduled_at:
          type: string
          format: date-time
          description: >-
            Present when a scheduled_at value was stored. Persists even after
            the scheduled send has been processed or cancelled.
        inline_css:
          type: boolean
          description: >-
            Present when true in the immediate create response. Not persisted;
            absent on subsequent GET requests.
        sandbox:
          type: boolean
          description: Present when sandbox mode was used.
        recipient_statuses:
          type: object
          description: >
            Per-status recipient counts for the message. Present only for
            outbound messages

            with recipient rows. Keys are recipient statuses, values are counts.

            Example: `{"delivered": 998, "bounced": 2}`.
          additionalProperties:
            type: integer
          example:
            delivered: 998
            bounced: 2
      required:
        - record_type
        - id
        - status
        - from
        - to
        - cc
        - bcc
        - subject
        - reply_to
        - template_id
        - template_variables
        - attachments
        - events
        - created_at
    SuppressedRecipient:
      type: object
      properties:
        to:
          type: string
          format: email
          description: Suppressed recipient email address.
        reason:
          type: string
          description: Suppression reason returned by the recipient suppression service.
        scope:
          type: string
          description: Scope at which the suppression applies.
        override_allowed:
          type: boolean
          description: Whether an authorized send may override this suppression.
      required:
        - to
        - reason
        - scope
        - override_allowed
    ErrorObject:
      type: object
      properties:
        code:
          type: string
          description: >-
            Telnyx error code. Edge idempotency errors use 10027 or 10036.
            Fallback 404/500 responses from the framework may use string status
            codes ('404', '500') instead.
          enum:
            - '10001'
            - '10006'
            - '10007'
            - '10015'
            - '10016'
            - '10019'
            - recipient_suppressed
            - reputation_suspended
            - '404'
            - '500'
            - '10027'
            - '10036'
        title:
          type: string
        detail:
          description: >-
            Human-readable error detail. Changeset responses may return a
            structured object.
          oneOf:
            - type: string
            - type: object
              additionalProperties: true
        source:
          type:
            - object
            - 'null'
          additionalProperties: true
        meta:
          type:
            - object
            - 'null'
          additionalProperties: true
          description: Additional metadata. Present on 401 errors with a documentation URL.
      required:
        - code
        - title
        - detail
    RenderErrorObject:
      type: object
      properties:
        code:
          type: string
          enum:
            - render_error
        message:
          type: string
      required:
        - code
        - message
    EmailAddress:
      type: object
      properties:
        email:
          type: string
        name:
          type: string
      required:
        - email
    EmailMessageStatus:
      type: string
      description: >-
        Current status of an email message. Lifecycle statuses (queued,
        scheduled, etc.) are set on creation. Delivery statuses (delivered,
        bounced, etc.) are updated by delivery event consumers.
      enum:
        - queued
        - scheduled
        - cancelled
        - sandbox
        - sending
        - sent
        - failed
        - deferred
        - delivered
        - bounced
        - complained
        - rejected
        - opened
        - clicked
        - unsubscribed
    AttachmentResponse:
      type: object
      description: EDR-aligned attachment metadata. The base64 `content` is never returned.
      properties:
        url:
          type:
            - string
            - 'null'
          format: uri
          description: Telnyx-hosted public URL for the attachment content.
        sha256:
          type:
            - string
            - 'null'
          description: SHA-256 hex digest of the attachment content.
        size_bytes:
          type:
            - integer
            - 'null'
          description: Attachment size in bytes.
        filename:
          type: string
        content_type:
          type: string
        disposition:
          type: string
          default: attachment
          description: >-
            MIME disposition (e.g. `attachment` or `inline`). Runtime passes
            through the stored value without enforcing an enum.
        content_id:
          type:
            - string
            - 'null'
          description: MIME Content-ID for inline references.
      required:
        - url
        - sha256
        - size_bytes
        - filename
        - content_type
        - disposition
        - content_id
    MessageEvent:
      type: object
      properties:
        type:
          $ref: '#/components/schemas/EmailEventType'
        occurred_at:
          type: string
          format: date-time
        payload:
          type: object
          additionalProperties: true
      required:
        - type
        - occurred_at
    EmailEventType:
      type: string
      enum:
        - queued
        - deferred
        - scheduled
        - cancelled
        - sandbox
        - sending
        - sent
        - failed
        - delivered
        - bounced
        - complained
        - rejected
        - opened
        - clicked
        - unsubscribed
        - daily_limit_exceeded
  headers:
    IdempotentReplayed:
      description: >-
        Present with value `true` when Edge replayed a stored successful
        response for the supplied Idempotency-Key. Omitted for first-time
        requests and error responses.
      schema:
        type: boolean
        enum:
          - true
        example: true
  responses:
    email_UnauthorizedResponse:
      description: Not authorized (10006).
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/email_ErrorResponse'
          example:
            errors:
              - code: '10006'
                title: Not authorized
                detail: Invalid API key
                meta:
                  url: https://developers.telnyx.com/docs/overview/errors/10006
    email_ForbiddenResponse:
      description: >-
        Forbidden (10007), such as domain not verified, suspended, degraded, or
        missing DKIM.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/email_ErrorResponse'
          example:
            errors:
              - code: '10007'
                title: Forbidden
                detail: >-
                  Domain is not verified. Complete DNS setup before sending
                  email.
    email_NotFoundResponse:
      description: Resource not found (10001).
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/email_ErrorResponse'
          example:
            errors:
              - code: '10001'
                title: Not Found
                detail: The requested resource was not found
    IdempotencyConflictResponse:
      description: >-
        A request with the same Idempotency-Key is still being processed
        (10036). Retry later with the same key and request.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/email_ErrorResponse'
          example:
            errors:
              - code: '10036'
                title: Resource is being processed
                detail: >-
                  A request with this Idempotency-Key is already being
                  processed.
                source:
                  pointer: /header/Idempotency-Key
    PayloadTooLargeResponse:
      description: Request body exceeds the 8,000,000-byte limit for this endpoint.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/email_ErrorResponse'
    email_ServiceUnavailableResponse:
      description: >-
        Service unavailable (10016), including an unavailable upstream
        dependency or unavailable Edge idempotency protection for a keyed
        request.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/email_ErrorResponse'
          example:
            errors:
              - code: '10016'
                title: Service Unavailable
                detail: >-
                  The email domain service is temporarily unavailable. Please
                  try again later.
  securitySchemes:
    bearerAuth:
      scheme: bearer
      type: http

````