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

# Send an email

> Sends a transactional email through the durable organization-scoped idempotency ledger. Exact retries return the persisted canonical result; payload drift returns 409. Each attachment must include exactly one of content (base64) or path (URL). Requires scope: emails:send



## OpenAPI

````yaml /api-specs/services.json post /email/v1/messages
openapi: 3.1.0
info:
  title: Voyant Cloud REST API
  version: 1.0.0
  description: >-
    Public REST API for Voyant Cloud products: Vault, SMS, Email, Verification,
    Video, Realtime, and Browser. All requests authenticate with an API token
    passed as an HTTP bearer token in the Authorization header. Each operation
    requires a specific token scope, documented in the operation description.
servers:
  - url: https://api.voyant.travel
    description: Production
security:
  - bearerAuth: []
tags:
  - name: Vault
    description: >-
      Encrypted secret storage and envelope/per-call cryptography scoped to an
      organization vault.
  - name: SMS
    description: Send SMS messages and inspect message history and phone numbers.
  - name: Email
    description: Send transactional email and inspect message history.
  - name: Verification
    description: >-
      Start and check one-time-code verifications across SMS, call, email, and
      WhatsApp.
  - name: Video
    description: >-
      Upload, manage, caption, and watermark videos, and mint signed playback
      tokens.
  - name: Realtime
    description: >-
      Publish messages to realtime channels, inspect history and presence, and
      mint short-lived subscriber tokens.
  - name: Browser
    description: >-
      Headless browser rendering, scraping, structured extraction, crawling, and
      interactive sessions.
paths:
  /email/v1/messages:
    post:
      tags:
        - Email
      summary: Send an email
      description: >-
        Sends a transactional email through the durable organization-scoped
        idempotency ledger. Exact retries return the persisted canonical result;
        payload drift returns 409. Each attachment must include exactly one of
        content (base64) or path (URL). Requires scope: emails:send
      operationId: sendEmailMessage
      parameters:
        - name: Idempotency-Key
          in: header
          required: true
          schema:
            type: string
            minLength: 1
            maxLength: 256
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/SendEmailInput'
      responses:
        '201':
          description: Email queued
          content:
            application/json:
              schema:
                type: object
                required:
                  - data
                properties:
                  data:
                    $ref: '#/components/schemas/EmailDeliveryResult'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '409':
          $ref: '#/components/responses/Conflict'
        '429':
          $ref: '#/components/responses/TooManyRequests'
        '500':
          $ref: '#/components/responses/ServerError'
        '503':
          $ref: '#/components/responses/ServiceUnavailable'
      x-codeSamples:
        - lang: typescript
          label: SDK
          source: >-
            import { createVoyantCloudClient } from "@voyant-travel/cloud-sdk";


            const cloud = createVoyantCloudClient({ apiKey:
            process.env.VOYANT_API_KEY });


            const message = await cloud.email.sendMessage({
              idempotencyKey: "email-attempt-123",
              ...{
              "from": "noreply@updates.example.com",
              "to": [
                "<string>"
              ],
              "cc": "<string>",
              "bcc": "<string>",
              "replyTo": "<string>",
              "subject": "<string>",
              "html": "<string>",
              "text": "<string>",
              "attachments": "<string>"
            }

            });
        - lang: bash
          label: cURL
          source: |-
            curl --request POST \
              --url https://api.voyant.travel/email/v1/messages \
              --header 'Authorization: Bearer <token>' \
              --header 'Idempotency-Key: email-attempt-123' \
              --header 'Content-Type: application/json' \
              --data '{
              "from": "noreply@updates.example.com",
              "to": [
                "<string>"
              ],
              "cc": "<string>",
              "bcc": "<string>",
              "replyTo": "<string>",
              "subject": "<string>",
              "html": "<string>",
              "text": "<string>",
              "attachments": "<string>"
            }'
        - lang: javascript
          label: Node
          source: >-
            const response = await
            fetch("https://api.voyant.travel/email/v1/messages", {
              method: "POST",
              headers: {
                "Content-Type": "application/json",
                "Authorization": "Bearer <token>",
                "Idempotency-Key": "email-attempt-123"
              },
              body: JSON.stringify({
                "from": "noreply@updates.example.com",
                "to": [
                  "<string>"
                ],
                "cc": "<string>",
                "bcc": "<string>",
                "replyTo": "<string>",
                "subject": "<string>",
                "html": "<string>",
                "text": "<string>",
                "attachments": "<string>"
              }),
            });


            const data = await response.json();
        - lang: python
          label: Python
          source: |-
            import requests

            response = requests.post(
                "https://api.voyant.travel/email/v1/messages",
                headers={
                    "Authorization": "Bearer <token>",
                    "Idempotency-Key": "email-attempt-123"
                },
                json={
                    "from": "noreply@updates.example.com",
                    "to": [
                        "<string>"
                    ],
                    "cc": "<string>",
                    "bcc": "<string>",
                    "replyTo": "<string>",
                    "subject": "<string>",
                    "html": "<string>",
                    "text": "<string>",
                    "attachments": "<string>"
                }
            )

            data = response.json()
components:
  schemas:
    SendEmailInput:
      type: object
      required:
        - from
        - to
        - subject
      properties:
        from:
          type: string
          minLength: 3
          maxLength: 320
          example: noreply@updates.example.com
        to:
          type: array
          minItems: 1
          maxItems: 50
          items:
            type: string
            format: email
        cc:
          type:
            - array
            - 'null'
          maxItems: 50
          items:
            type: string
            format: email
        bcc:
          type:
            - array
            - 'null'
          maxItems: 50
          items:
            type: string
            format: email
        replyTo:
          type:
            - array
            - 'null'
          maxItems: 5
          items:
            type: string
            format: email
        subject:
          type: string
          minLength: 1
          maxLength: 998
        html:
          type:
            - string
            - 'null'
          maxLength: 1000000
        text:
          type:
            - string
            - 'null'
          maxLength: 1000000
        attachments:
          type:
            - array
            - 'null'
          maxItems: 20
          items:
            $ref: '#/components/schemas/SendEmailAttachment'
    EmailDeliveryResult:
      type: object
      required:
        - protocolVersion
        - operationId
        - backendIdentity
        - accountIdentity
        - acceptedCount
        - message
      properties:
        protocolVersion:
          type: string
          const: voyant-cloud-email-idempotency/v1
        operationId:
          type: string
        backendIdentity:
          type: string
        accountIdentity:
          type: string
        acceptedCount:
          type: integer
          const: 1
        message:
          $ref: '#/components/schemas/EmailMessageSummary'
    SendEmailAttachment:
      type: object
      required:
        - filename
      description: >-
        Each attachment must include exactly one of `content` (base64) or `path`
        (URL).
      properties:
        filename:
          type: string
          minLength: 1
          maxLength: 255
        content:
          type: string
          description: Base64-encoded file bytes.
        path:
          type: string
          format: uri
          description: Public URL the provider will fetch.
        contentType:
          type: string
          maxLength: 255
        contentId:
          type: string
          maxLength: 255
          description: 'Content-ID for inline images referenced via cid: in HTML.'
    EmailMessageSummary:
      type: object
      required:
        - id
        - organizationId
        - fromAddress
        - toAddresses
        - subject
        - status
        - createdAt
        - updatedAt
      properties:
        id:
          type: string
        organizationId:
          type: string
        fromAddress:
          type: string
        toAddresses:
          type: array
          items:
            type: string
        ccAddresses:
          type: array
          items:
            type: string
        bccAddresses:
          type: array
          items:
            type: string
        replyTo:
          type: array
          items:
            type: string
        subject:
          type: string
        status:
          type: string
          enum:
            - queued
            - sent
            - delivered
            - delivery_delayed
            - bounced
            - complained
            - opened
            - clicked
            - failed
        openCount:
          type: integer
        clickCount:
          type: integer
        providerEmailId:
          type:
            - string
            - 'null'
        providerStatus:
          type:
            - string
            - 'null'
        errorMessage:
          type:
            - string
            - 'null'
        sentAt:
          type:
            - string
            - 'null'
          format: date-time
        deliveredAt:
          type:
            - string
            - 'null'
          format: date-time
        lastEventAt:
          type:
            - string
            - 'null'
          format: date-time
        createdAt:
          type: string
          format: date-time
        updatedAt:
          type: string
          format: date-time
    Error:
      type: object
      properties:
        error:
          type: string
    RateLimitError:
      type: object
      required:
        - error
      properties:
        error:
          type: string
        retryAfterMs:
          type: integer
          description: Milliseconds to wait before retrying.
  responses:
    BadRequest:
      description: Invalid request
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
    Unauthorized:
      description: Authentication is missing, invalid, revoked, or expired.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
    Forbidden:
      description: The API token does not include a scope required for this operation.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
    Conflict:
      description: The request conflicts with the current state of the resource.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
    TooManyRequests:
      description: Rate limit exceeded.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/RateLimitError'
    ServerError:
      description: An unexpected error occurred.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
    ServiceUnavailable:
      description: >-
        A required dependency (for example the platform database) is not
        available.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      description: >-
        Voyant Cloud API token, passed as `Authorization: Bearer <token>`. Each
        token carries a fixed set of scopes; an operation rejects tokens missing
        its required scope.

````