messages commands let you send, list, inspect and cancel email messages; this page covers their arguments and flags.
Before running the examples, log in with a full API key, use your verified sender domain, and replace YOUR_RESOURCE_ID with a template ID or message ID from your test account, as each example needs. Create any named content, recipient, attachment, or JSON files first. Shell examples use Bash; examples that read JSON with jq need jq installed. Sends use sandbox mode.
Overview
send- Send an email messagelist- List messagesget- Get one messagecancel- Cancel a scheduled message
Send Messages
--from, --subject, a recipient (--to or --recipients) and text or HTML content. A send with --template-id needs only a recipient, because the template supplies the rest; see Stored Templates. When a value is missing, the command can ask for it; see prompts. The command checks every flag and file before it sends anything, so invalid input sends nothing.
Basic Usage
Sender and Reply-To
--from-name sets the sender’s display name and needs --from. --reply-to sets the address that replies go to. You cannot also set Reply-To with --header.
Recipients
Use--to for a simple list of recipients. You can use it multiple times, and each value is split on commas. Use --recipients for a CSV or JSON file that gives each recipient a name and substitutions. You cannot combine --to and --recipients.
Content
Give each part of the content inline or from a file, not both:
Text or HTML content is required. AMP content is an extra part that goes with one of them. Several parts together make a multipart email.
{{first_name}}, which the API fills from --global-substitutions and the recipients file. See the message content guide.
Stored Templates
--template-id sends a transactional template stored in your AhaSend account. Manage stored templates with the ahasend templates commands.
- The template supplies the content, so you cannot use
--text,--html,--amp,--text-file,--html-fileor--amp-filewith it. --fromand--subjectare optional. Without them, the template’s sender and subject apply.- The values of
--global-substitutionsare copied into each recipient’s substitutions. A recipient’s own value for the same key wins.
Attachments
--attach attaches a regular file, and you can use it multiple times. Each file can be at most 10,485,760 bytes (10 MiB), and the CLI detects its MIME type. Every request carries every attachment. Together, base64-encoded, the attachments can take at most 29 MB of a request; a larger set fails before anything is sent.
Scheduling
--schedule takes an RFC 3339 time in UTC, in the form YYYY-MM-DDTHH:MM:SSZ, or a relative time from now, such as 30m or 2h. The API takes a future time within 7 days. A time in the past or later than that fails before anything is sent.
Headers, Tags and Tracking
--headeradds a custom header inName: valueformat. You can use it multiple times, with each name once, in any case. Put a value that holds a comma in double quotes, such as--header '"Name: a, b"'. The command refusesFrom,Sender,To,Cc,Bcc,Subject,Message-IDand the headers AhaSend sets, such asAhaSend-Sandbox; use the matching flag instead, such as--from,--sandboxor--tag.--tagadds a message tag. You can use it multiple times.--track-opensand--track-clicksturn tracking on;--track-opens=falseand--track-clicks=falseturn it off. Without the flags, your account’s tracking setting applies.
Sandbox Mode
--sandbox sends in sandbox mode, which delivers nothing. --sandbox-result picks the simulated outcome: deliver (the default), bounce, defer, fail or suppress. It needs --sandbox. See sandbox mode.
Idempotency
--idempotency-key makes a retry safe: the API does not act twice on the same request with the same key. Without the flag, the command generates a key. The API keeps a send’s result for its key for 24 hours. Reuse a key only to retry the identical request; see idempotency.
Output and Exit Codes
A send of up to 100 recipients makes one request. Plain output starts with a heading,Message sent successfully, Message sent to N of M recipients or Message not sent to any recipient, then lists each message:
--output json, the command prints the API’s response body as JSON output describes. Each message’s id is its Message-ID, which messages get and messages cancel take. Notices, such as where the command saved failed recipients, go to stderr.
The API can accept a request but refuse some recipients in it, when it could not queue their message. Those recipients count as failed. The command saves failed recipients to a file that you can send again; see failed recipients.
The API does not refuse a suppressed address. It queues the message, does not deliver it, and gives the message the status suppressed, which messages list --status suppressed finds. AhaSend also sends a message.suppressed event to your webhooks.
A send exits with the shared exit codes. Exit codes for sends gives the codes that report its result.
List Messages
--sendermatches the sender address exactly.--recipientand--subjectmatch every message whose recipient or subject contains the value, case-sensitively, so--recipient user@example.comalso matchesolduser@example.com.--statuscan be used multiple times. Valid statuses arereceived,delivered,opened,clicked,deferred,bounced,failed,suppressed,sandbox delivered,sandbox deferred,sandbox failed,sandbox bouncedandsandbox suppressed.deliveredalso matches opened and clicked messages, andopenedalso matches clicked ones.--tagtakes at most 20 tags, none with a comma.--from-timeand--to-timetake an RFC 3339 time or a relative time that counts back from now, such as1h,24hor7d.--limit,--afterand--beforepage through the results as lists and pagination describes. With--output json, read the next cursor frompagination.next_cursor.--show-detailsadds more fields for each message, such as its direction, attempts and bounce class.
Get a Message
<550e8400-e29b-41d4-a716-446655440000@example.com>. Quote a Message-ID in the shell. The output shows the message’s status, its delivery attempts, the template it was sent from, and its raw content while your retention settings keep it.
Cancel Messages
messages get.
The command asks for confirmation first; see prompts.
messages get and messages cancel cannot find it and exit with code 5; try again shortly.
With several IDs, the command cancels each in turn and prints one result per ID; with --output json, it prints a JSON array with the API’s response or error body for each ID, or the CLI’s error object for an ID whose request got no answer. Any failure then exits with code 1. Ctrl+C stops before the next cancel and exits with code 130.
Advanced Usage
- Batch Processing Guide - Send to many recipients from a CSV or JSON file
- Message Content Guide - Content files, variables, conditions and loops
- Stored Templates - Manage the transactional templates that
--template-idsends - Examples - Real-world use cases
Command Flags
These flags come from the CLI’s--help. All commands also accept the global flags.

