Skip to content

Outbound Email

/api

The Outbound Email API lets you send email from Mailisk namespaces, reply to inbound emails, forward inbound emails, and inspect delivery status and provider events.

Endpoints

MethodEndpointDescription
POST/api/emails/sendSend a new outbound email
GET/api/emails/outbound/{outboundEmailId}Get outbound email status
POST/api/emails/{emailId}/replyReply to an inbound email
POST/api/emails/{emailId}/forwardForward an inbound email

Sending rules

  • Recipients must be verified external destinations or addresses under the same namespace.
  • Sender overrides must belong to the requested namespace, for example support@mynamespace.mailisk.net.
  • If from is omitted, Mailisk sends from outbound-delivery@{namespace}.mailisk.net.
  • New outbound emails and replies require at least one recipient and either html or text content.
  • Messages sent only to same-namespace recipients do not consume outbound usage because they are counted as inbound email when delivered. Messages with any external recipient consume outbound usage.
  • Attachments must be base64 encoded. Use application/octet-stream when you need the file to remain a downloadable attachment across mail clients and parsers.
  • Outbound emails can include at most 20 attachments, and the total encoded message size must not exceed 5 MB.

Send Outbound Email

POST /api/emails/send

This endpoint creates and queues a new outbound email from a namespace.

sh
curl --request POST \
     --url 'https://api.mailisk.com/api/emails/send?namespace=mynamespace' \
     --header 'Accept: application/json' \
     --header 'Content-Type: application/json' \
     --header 'X-Api-Key: {Api Key}' \
     --data '{
       "from": {
         "email": "support@mynamespace.mailisk.net",
         "name": "Support"
       },
       "to": ["customer@mynamespace.mailisk.net"],
       "subject": "Hello from Mailisk",
       "text": "This is the plain text body.",
       "html": "<p>This is the HTML body.</p>"
     }'
js
const outboundEmail = await mailisk.sendEmail("mynamespace", {
  from: {
    email: "support@mynamespace.mailisk.net",
    name: "Support",
  },
  to: ["customer@mynamespace.mailisk.net"],
  subject: "Hello from Mailisk",
  text: "This is the plain text body.",
  html: "<p>This is the HTML body.</p>",
});

Query

NameRequiredTypeDescription
namespaceRequiredStringThe namespace to send from.

Body

NameRequiredTypeDescription
fromOptionalOutboundEmailAddressSender override. The email address must belong to the requested namespace.
reply_toOptionalOutboundEmailAddressReply-To address for the outbound message.
toOptionalString[]Primary recipients. At least one recipient across to, cc, or bcc is required.
ccOptionalString[]Carbon copy recipients.
bccOptionalString[]Blind carbon copy recipients.
subjectRequiredStringEmail subject. Maximum length is 998 characters.
htmlOptionalStringHTML body. Either html or text is required.
textOptionalStringPlain text body. Either html or text is required.
attachmentsOptionalOutboundEmailAttachment[]Attachments encoded with base64 content. At most 20 attachments are allowed.

Sending attachments

Encode file bytes as base64 in content_base64.

js
const fs = require("node:fs");

const content = fs.readFileSync("report.txt");

await mailisk.sendEmail("mynamespace", {
  to: ["customer@mynamespace.mailisk.net"],
  subject: "Report",
  text: "Attached.",
  attachments: [
    {
      filename: "report.txt",
      content_type: "application/octet-stream",
      content_base64: content.toString("base64"),
    },
  ],
});

When sending to a same-namespace address, use Search Inbox and Get Attachment to confirm that the message and attachment arrived.

Response

json
{
  "id": "5a6205b2-2538-4744-b63f-f43e3d60b79f",
  "organisation_id": "67f3dcb7-a707-422b-a907-5da53f026fe3",
  "type": "new",
  "status": "queued",
  "from": {
    "email": "support@mynamespace.mailisk.net",
    "name": "Support"
  },
  "subject": "Hello from Mailisk",
  "recipient_count": 1,
  "attachment_count": 0,
  "message_id": "<5a6205b2-2538-4744-b63f-f43e3d60b79f@mynamespace.mailisk.net>",
  "queued_at": "2026-04-28T08:24:58.000Z",
  "created_at": "2026-04-28T08:24:58.000Z",
  "updated_at": "2026-04-28T08:24:58.000Z"
}

Get Outbound Email

GET /api/emails/outbound/{outboundEmailId}

This endpoint returns the current delivery state for an outbound email, including recipient statuses, a delivery summary, and provider delivery events.

sh
curl --request GET \
     --url https://api.mailisk.com/api/emails/outbound/{outboundEmailId} \
     --header 'Accept: application/json' \
     --header 'X-Api-Key: {Api Key}'
js
const outboundEmail = await mailisk.getOutboundEmail(outboundEmailId);

Path Params

NameDescription
outboundEmailIdThe outbound email UUID to fetch.

Response

json
{
  "id": "5a6205b2-2538-4744-b63f-f43e3d60b79f",
  "organisation_id": "67f3dcb7-a707-422b-a907-5da53f026fe3",
  "type": "new",
  "status": "sent",
  "from": {
    "email": "support@mynamespace.mailisk.net",
    "name": "Support"
  },
  "subject": "Hello from Mailisk",
  "recipient_count": 1,
  "attachment_count": 0,
  "message_id": "<5a6205b2-2538-4744-b63f-f43e3d60b79f@mynamespace.mailisk.net>",
  "provider": "mailisk",
  "provider_message_id": "provider-message-id",
  "queued_at": "2026-04-28T08:24:58.000Z",
  "sent_at": "2026-04-28T08:25:01.000Z",
  "created_at": "2026-04-28T08:24:58.000Z",
  "updated_at": "2026-04-28T08:25:01.000Z",
  "delivery_summary": {
    "pending": 0,
    "accepted": 0,
    "queued": 0,
    "sent": 1,
    "delayed": 0,
    "deferred": 0,
    "delivered": 0,
    "bounced": 0,
    "expired": 0,
    "complained": 0,
    "unsubscribed": 0,
    "suppressed": 0,
    "rejected": 0,
    "failed": 0,
    "cancelled": 0
  },
  "recipients": [
    {
      "id": "af0957ab-45bb-4b71-8b84-041407a9e13a",
      "type": "to",
      "email": "customer@mynamespace.mailisk.net",
      "delivery_status": "sent",
      "sent_at": "2026-04-28T08:25:01.000Z",
      "attempt_count": 1
    }
  ],
  "events": [
    {
      "id": "e049fd60-49fb-46c6-9bf5-4453c5ebfc4d",
      "provider": "mailisk",
      "provider_message_id": "provider-message-id",
      "provider_event_id": "provider-event-id",
      "event_type": "delivered",
      "occurred_at": "2026-04-28T08:25:03.000Z",
      "recipients": [
        {
          "id": "9c9aa979-4674-4750-a952-6d7b235418d8",
          "outbound_email_recipient_id": "af0957ab-45bb-4b71-8b84-041407a9e13a",
          "email": "customer@mynamespace.mailisk.net",
          "attempt_count": 1
        }
      ],
      "created_at": "2026-04-28T08:25:03.000Z"
    }
  ]
}

Reply to Email

POST /api/emails/{emailId}/reply

This endpoint creates and queues a reply to an inbound email. Mailisk derives the reply recipient and threading headers from the source email. If subject is omitted, Mailisk uses Re: {original subject}.

sh
curl --request POST \
     --url https://api.mailisk.com/api/emails/{emailId}/reply \
     --header 'Accept: application/json' \
     --header 'Content-Type: application/json' \
     --header 'X-Api-Key: {Api Key}' \
     --data '{
       "text": "Thanks, we received your message."
     }'
js
const reply = await mailisk.replyToEmail(emailId, {
  text: "Thanks, we received your message.",
});

Path Params

NameDescription
emailIdThe inbound email ID returned by Search Inbox.

Body

NameRequiredTypeDescription
fromOptionalOutboundEmailAddressSender override. The email address must belong to the inbound email namespace.
ccOptionalString[]Carbon copy recipients.
bccOptionalString[]Blind carbon copy recipients.
subjectOptionalStringReply subject. Defaults to Re: {original subject}.
htmlOptionalStringHTML reply body. Either html or text is required.
textOptionalStringPlain text reply body. Either html or text is required.
attachmentsOptionalOutboundEmailAttachment[]Reply attachments encoded with base64 content. At most 20 attachments are allowed.

Response

Returns an OutboundEmailResponse. See the Send Outbound Email response for the common response shape.

Forward an Email

POST /api/emails/{emailId}/forward

This endpoint creates and queues a forwarded copy of an inbound email. The to list is required. Optional html or text content is prepended before the forwarded message.

sh
curl --request POST \
     --url https://api.mailisk.com/api/emails/{emailId}/forward \
     --header 'Accept: application/json' \
     --header 'Content-Type: application/json' \
     --header 'X-Api-Key: {Api Key}' \
     --data '{
       "to": ["customer@mynamespace.mailisk.net"],
       "text": "Forwarding this along."
     }'
js
const forwarded = await mailisk.forwardEmail(emailId, {
  to: ["customer@mynamespace.mailisk.net"],
  text: "Forwarding this along.",
});

Path Params

NameDescription
emailIdThe inbound email ID returned by Search Inbox.

Body

NameRequiredTypeDescription
fromOptionalOutboundEmailAddressSender override. The email address must belong to the inbound email namespace.
toRequiredString[]Recipients to forward the message to.
ccOptionalString[]Carbon copy recipients.
bccOptionalString[]Blind carbon copy recipients.
subjectOptionalStringForwarded email subject. Defaults to Fwd: {original subject}.
htmlOptionalStringOptional HTML content to prefix before the forwarded message.
textOptionalStringOptional plain text content to prefix before the forwarded message.

Response

Returns an OutboundEmailResponse. See the Send Outbound Email response for the common response shape.

Typescript types

typescript
type OutboundEmailType = 'new' | 'reply' | 'forward';

type OutboundEmailStatus = 'queued' | 'sending' | 'sent' | 'failed';

type OutboundEmailRecipientType = 'to' | 'cc' | 'bcc';

type OutboundEmailRecipientDeliveryStatus =
  | 'pending'
  | 'accepted'
  | 'queued'
  | 'sent'
  | 'delayed'
  | 'deferred'
  | 'delivered'
  | 'bounced'
  | 'expired'
  | 'complained'
  | 'unsubscribed'
  | 'suppressed'
  | 'rejected'
  | 'failed'
  | 'cancelled';

type OutboundEmailEventType =
  | 'accepted'
  | 'queued'
  | 'sent'
  | 'failed'
  | 'rejected'
  | 'delayed'
  | 'deferred'
  | 'delivered'
  | 'bounced'
  | 'expired'
  | 'complained'
  | 'unsubscribed'
  | 'suppressed'
  | 'cancelled'
  | 'opened'
  | 'clicked';

interface OutboundEmailAddress {
  /** Email address */
  email: string;
  /** Display name, if one is specified */
  name?: string;
}

interface OutboundEmailAttachment {
  /** Attachment filename shown to recipients */
  filename: string;
  /** MIME type for the attachment */
  content_type: string;
  /** Base64 encoded file bytes */
  content_base64: string;
  /** Optional Content-ID for inline attachments */
  content_id?: string;
  /** Attachment disposition */
  disposition?: 'attachment' | 'inline';
}

interface SendOutboundEmailRequest {
  from?: OutboundEmailAddress;
  reply_to?: OutboundEmailAddress;
  to?: string[];
  cc?: string[];
  bcc?: string[];
  subject: string;
  html?: string;
  text?: string;
  attachments?: OutboundEmailAttachment[];
}

interface ReplyOutboundEmailRequest {
  from?: OutboundEmailAddress;
  cc?: string[];
  bcc?: string[];
  subject?: string;
  html?: string;
  text?: string;
  attachments?: OutboundEmailAttachment[];
}

interface ForwardOutboundEmailRequest {
  from?: OutboundEmailAddress;
  to: string[];
  cc?: string[];
  bcc?: string[];
  subject?: string;
  html?: string;
  text?: string;
}

interface OutboundEmailResponse {
  /** Unique identifier for the outbound email */
  id: string;
  /** Unique identifier for the organisation */
  organisation_id: string;
  /** Outbound email type */
  type: OutboundEmailType;
  /** Current email queue status */
  status: OutboundEmailStatus;
  /** Sender */
  from: OutboundEmailAddress;
  /** Reply-To address */
  reply_to?: OutboundEmailAddress;
  /** Subject */
  subject: string;
  /** Number of recipients */
  recipient_count: number;
  /** Number of attachments */
  attachment_count: number;
  /** Message-ID header */
  message_id: string;
  /** Delivery provider name */
  provider?: string;
  /** Provider message ID */
  provider_message_id?: string;
  /** Failure reason if the message failed */
  failure_reason?: string;
  queued_at: string;
  sending_at?: string;
  sent_at?: string;
  failed_at?: string;
  created_at: string;
  updated_at: string;
}

interface OutboundEmailDeliverySummary {
  pending: number;
  accepted: number;
  queued: number;
  sent: number;
  delayed: number;
  deferred: number;
  delivered: number;
  bounced: number;
  expired: number;
  complained: number;
  unsubscribed: number;
  suppressed: number;
  rejected: number;
  failed: number;
  cancelled: number;
}

interface OutboundEmailRecipient {
  id: string;
  type: OutboundEmailRecipientType;
  email: string;
  name?: string;
  delivery_status: OutboundEmailRecipientDeliveryStatus;
  last_event_type?: string;
  last_event_at?: string;
  accepted_at?: string;
  queued_at?: string;
  sent_at?: string;
  delayed_at?: string;
  deferred_at?: string;
  delivered_at?: string;
  bounced_at?: string;
  expired_at?: string;
  complained_at?: string;
  unsubscribed_at?: string;
  suppressed_at?: string;
  rejected_at?: string;
  failed_at?: string;
  cancelled_at?: string;
  last_smtp_code?: string;
  last_enhanced_status_code?: string;
  last_smtp_response?: string;
  attempt_count: number;
  bounce_type?: string;
  bounce_subtype?: string;
  bounce_classification?: string;
  complaint_feedback_type?: string;
}

interface OutboundEmailDetailResponse extends OutboundEmailResponse {
  delivery_summary: OutboundEmailDeliverySummary;
  recipients: OutboundEmailRecipient[];
  events: OutboundEmailEvent[];
}

interface OutboundEmailEventRecipient {
  id: string;
  outbound_email_recipient_id?: string;
  email: string;
  smtp_code?: string;
  enhanced_status_code?: string;
  smtp_response?: string;
  diagnostic_code?: string;
  action?: string;
  attempt_count?: number;
  bounce_classification?: string;
}

interface OutboundEmailEvent {
  id: string;
  provider: string;
  provider_message_id?: string;
  provider_event_id?: string;
  event_type: OutboundEmailEventType;
  event_subtype?: string;
  occurred_at: string;
  recipients: OutboundEmailEventRecipient[];
  created_at: string;
}