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

# Attachments

> Learn how to attach files to your emails.

## Adding attachments

The `attachments` array attaches files to your email. Each entry is an object with three fields: the MIME
`type` of the file, the `filename` shown to the recipient, and `content` containing the file's bytes as a
base64-encoded string.

<CodeGroup>
  ```bash cURL theme={null}
  #!/usr/bin/env bash
  set -u
  : "${MAILCHANNELS_API_KEY:?Set MAILCHANNELS_API_KEY before running}"
  : "${FROM_EMAIL:?Set FROM_EMAIL (must be on a Domain-Lockdown-authorized domain)}"
  : "${TO_EMAIL:?Set TO_EMAIL}"
  : "${ATTACHMENT_PATH:?Set ATTACHMENT_PATH to the file you want to attach, e.g. ./logo.png}"

  # Base64-encode the file. The -w0 flag (GNU base64) emits a single line with no
  # wrapping; on macOS, drop -w0 — `base64` there doesn't wrap by default.
  ATTACHMENT_BASE64=$(base64 -w0 "$ATTACHMENT_PATH")
  ATTACHMENT_FILENAME=$(basename "$ATTACHMENT_PATH")

  curl -X POST https://api.mailchannels.net/tx/v1/send \
    -H "Content-Type: application/json" \
    -H "X-Api-Key: $MAILCHANNELS_API_KEY" \
    -d @- <<JSON
  {
    "personalizations": [
      { "to": [{ "email": "$TO_EMAIL", "name": "Recipient" }] }
    ],
    "from": {
      "email": "$FROM_EMAIL",
      "name": "Your Name"
    },
    "subject": "Hello from MailChannels",
    "content": [
      {
        "type": "text/plain",
        "value": "Hello! See the attached file."
      }
    ],
    "attachments": [
      {
        "type": "image/png",
        "filename": "$ATTACHMENT_FILENAME",
        "content": "$ATTACHMENT_BASE64"
      }
    ]
  }
  JSON
  ```

  ```javascript Node.js theme={null}
  import { readFile } from "node:fs/promises";
  import { basename } from "node:path";
  import { MailChannels } from "mailchannels-sdk";

  const { MAILCHANNELS_API_KEY, FROM_EMAIL, TO_EMAIL, ATTACHMENT_PATH } = process.env;
  if (!MAILCHANNELS_API_KEY) throw new Error("Set MAILCHANNELS_API_KEY before running");
  if (!FROM_EMAIL) throw new Error("Set FROM_EMAIL (must be on a Domain-Lockdown-authorized domain)");
  if (!TO_EMAIL) throw new Error("Set TO_EMAIL");
  if (!ATTACHMENT_PATH) throw new Error("Set ATTACHMENT_PATH to the file you want to attach, e.g. ./logo.png");

  const fileBytes = await readFile(ATTACHMENT_PATH);

  const mailchannels = new MailChannels(MAILCHANNELS_API_KEY);

  const { data, error } = await mailchannels.emails.send({
    from: { email: FROM_EMAIL, name: "Your Name" },
    to: { email: TO_EMAIL, name: "Recipient" },
    subject: "Hello from MailChannels",
    text: "Hello! See the attached file.",
    attachments: [
      {
        type: "image/png",
        filename: basename(ATTACHMENT_PATH),
        content: fileBytes.toString("base64"),
      },
    ],
  });

  if (error) {
    console.error("Send failed:", error);
    process.exit(1);
  }
  console.log(data);
  ```

  ```python Python theme={null}
  import os
  import sys
  from pathlib import Path

  import mailchannels

  if not os.environ.get("MAILCHANNELS_API_KEY"):
      sys.exit("Set MAILCHANNELS_API_KEY before running")

  from_email = os.environ.get("FROM_EMAIL")
  to_email = os.environ.get("TO_EMAIL")
  attachment_path = os.environ.get("ATTACHMENT_PATH")
  if not from_email:
      sys.exit("Set FROM_EMAIL (must be on a Domain-Lockdown-authorized domain)")
  if not to_email:
      sys.exit("Set TO_EMAIL")
  if not attachment_path:
      sys.exit("Set ATTACHMENT_PATH to the file you want to attach, e.g. ./logo.png")

  # Attachment.from_bytes base64-encodes the bytes and guesses the content type
  # from the filename.
  attachment = mailchannels.Attachment.from_bytes(
      Path(attachment_path).read_bytes(),
      filename=Path(attachment_path).name,
  )

  response = mailchannels.Emails.send(
      {
          "from": {"email": from_email, "name": "Your Name"},
          "to": [{"email": to_email, "name": "Recipient"}],
          "subject": "Hello from MailChannels",
          "text": "Hello! See the attached file.",
          "attachments": [attachment],
      }
  )

  print(response)
  ```

  ```php PHP theme={null}
  <?php

  require_once __DIR__ . '/vendor/autoload.php';

  use MailChannels\Client;

  $api_key         = getenv('MAILCHANNELS_API_KEY') or exit("Error: MAILCHANNELS_API_KEY is not set\n");
  $from_email      = getenv('FROM_EMAIL') or exit("Error: FROM_EMAIL is not set\n");
  $to_email        = getenv('TO_EMAIL') or exit("Error: TO_EMAIL is not set\n");
  $attachment_path = getenv('ATTACHMENT_PATH') or exit("Error: ATTACHMENT_PATH is not set\n");

  $client = new Client(apiKey: $api_key);

  $content = file_get_contents($attachment_path);
  if ($content === false) {
      exit("Error: could not read file: {$attachment_path}\n");
  }

  $mime = mime_content_type($attachment_path) ?: 'application/octet-stream';

  $response = $client->emails->send([
      'from'        => ['email' => $from_email, 'name' => 'Your Name'],
      'to'          => ['email' => $to_email, 'name' => 'Recipient'],
      'subject'     => 'Hello from MailChannels',
      'text'        => 'Hello! See the attached file.',
      'attachments' => [
          [
              'content'  => base64_encode($content),
              'filename' => basename($attachment_path),
              'type'     => $mime,
          ],
      ],
  ]);

  print_r($response->toArray());
  ```
</CodeGroup>

### Limits

* Up to 1000 attachments per email.
* 30 MB combined limit on attachments and email content. Messages that exceed this are rejected.

### Forbidden attachments

The following MIME types and file extensions are blocked because they are commonly associated with malware. Sending an
attachment with a forbidden type or extension returns an error.

**MIME types**

* `application/x-msdownload`
* `application/vnd.ms-htmlhelp`
* `application/java-archive`
* `application/x-sh`
* `application/x-shellscript`

**File extensions**

`.ade`, `.adp`, `.bat`, `.chm`, `.cmd`, `.com`, `.cpl`, `.exe`, `.hta`, `.ins`, `.isp`, `.jar`, `.jse`,
`.lib`, `.lnk`, `.mde`, `.msc`, `.msp`, `.mst`, `.pif`, `.scr`, `.sct`, `.sh`, `.shb`, `.sys`, `.vb`,
`.vbe`, `.vbs`, `.vxd`, `.wsc`, `.wsf`, `.wsh`

<Warning>
  Never send an attachment that you received from a user without first scanning it for viruses and malware.
</Warning>
