Skip to main content
This guide shows how to give ahasend messages send its content, from flags or files, and how to personalize it with substitutions.
To send a transactional template stored in your AhaSend account instead, see Stored Templates and the ahasend templates commands.
Before running the examples, log in with a full API key, use your verified sender domain, and replace YOUR_RESOURCE_ID with the ID of a published template in your test account. Create any named content, recipient, or JSON files first. Shell examples use Bash. Sends use sandbox mode.

Content Flags

Give each part of the message 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.
  • --text with --text-file, --html with --html-file, or --amp with --amp-file fails with exit code 4.

Substitution Basics

The subject and the content can hold placeholders in double curly braces. The AhaSend API fills them for each recipient with MiniJinja, which uses Jinja2-compatible syntax.
welcome.html
The values come from two places: A recipient’s own value for a key wins over the global value of the same key. The API HTML-escapes values in the HTML and AMP content, so send them as plain text. The subject, custom headers and the text content get values as they are. Use {{ name|safe }} only for HTML that your own code builds.

Substitution Types

Global Substitutions

Use global substitutions for values that are the same for every recipient. They work with --to and with --recipients.
company-data.json

Recipient Substitutions

Use a recipients file for values that differ per recipient. The file’s extension, .csv or .json, sets its format.
users.csv
The email column is required, and name sets the display name. The two headers can be in any case. Every other column is a substitution, and every value is trimmed. An empty cell sets no value, so the global value of the same name, if any, applies to that recipient.
A file with no recipients, an invalid address or an unknown JSON key fails with exit code 4 before anything is sent. For a bad entry, the error names its CSV row or JSON index. To send to many recipients, see batch processing.

Template Syntax Examples

Variables and Defaults

default gives a value to use when a variable is missing:
greeting.html

Conditional Content

conditional.html

Lists and Loops

A loop needs a list, so its values come from a JSON recipients file or the global substitutions file. CSV cells hold text only.
order-confirmation.html
orders.json

Stored Templates

--template-id sends a transactional template that is stored in your AhaSend account, instead of content from flags or files. Create, publish and inspect stored templates with the ahasend templates commands. ahasend templates get lists the variables that a send must supply.
  • The template supplies the content, so the content flags on this page cannot be used with --template-id.
  • --from and --subject are optional. Without them, the template’s sender and subject apply.
  • Substitutions work as on this page: the values of --global-substitutions are copied into each recipient’s substitutions, and a recipient’s own value wins.

Testing Content

Send to a test address in sandbox mode, which delivers nothing:
Then open the message in the AhaSend dashboard, or run ahasend messages get with its Message-ID to see its content. See messages get.

Best Practices

  1. Use meaningful variable names: {{ customer_first_name }}, not {{ fn }}.
  2. Provide default values: {{ name|default("Friend") }}.
  3. Test in sandbox mode: Send to a test address before a real send.
  4. Keep templates simple: Complex logic belongs in your application.
  5. Split global and recipient data: Company details go in the global file, personal details in the recipients file.

Next Steps