Set up a transactional email
UpdatedTransactional messages are email or push notifications that your audience implicitly opts-into, like a transaction receipt or a password reset request. You can send transactional messages programmatically through Customer.io.
New to transactional messaging?
Check out our getting started section to learn more about transactional concepts and how our transactional API works.
Before you begin
Before you can send transactional emails, you need to:
- Confirm your registration email and verify your account.
- Authenticate your sending domain. If you configured a custom SMTP server, contact us to manually authenticate your sending domain.
- Get your app API key. This is the bearer token that you’ll use when calling the transactional API. app API keys are not the same as the track API keys that you use to update profiles and trigger events. Customer.io does not store app API keys (only a hashed version) and you can restrict app API keys to specific IP addresses for extra security.
We also recommend that you use a different, specialized domain or subdomain for transactional messages. A sending domain is the domain of the “From email address” when you send emails, and you can request that we add your transactional domain to our specialized, transactional IP pool. Email providers like Gmail monitor the sending domain for unusual behavior and spam complaints. Separating your transactional domain from your marketing domain—something like marketing.example.com
and transactional.example.com
—prevents your marketing messages from affecting your critical transactional messages. Learn more about domain reputation.
Create a transactional email
Try our Postman collection!
You can use our Postman collection and associated environment to get started with the Customer.io API. Our environment is based on our US endpoints; if you’re in our EU region, you’ll need to add -eu
to track_api_url
and app_api_url
variables.
Go to the Transactional page and click Send your first message or Create message—depending on whether there are already transactional messages in your workspace.
Name your message and provide a description. These fields help your team members understand what kind of message this is (like “Password Reset Instructions”). You can also use the Name of your message instead of the
transactional_message_id
when you send your message.Click Add Content and set up your message. You’ll choose your editor or start from an existing email. When you build your email, you can personalize messages using attributes (
{{customer.<attribute>}}
) or API trigger data ({{trigger.<data-object-property>}}
) to customize your message.Configure your message settings.
Enable open and link tracking? Enable this setting if you need to know if people open or click links in your transactional messages.
Protect sensitive data by disabling message retention? This setting prevents Customer.io from retaining your message content in delivery history and associated API calls. You might want to do this to conceal sensitive content, like password reset tokens.
Queue messages as drafts? This setting generates a draft for every message you trigger, rather than sending them automatically. You can review these messages under the “Drafts” tab and decide whether to send or delete them.
Set a Trigger Name: This is a friendly name for your message that you can use instead of the
transactional_message_id
when you send your message. It may help make your integration more human-readable if you use triggers that represent the kinds of messages you send—likepassword reset
ororder confirmation
.
To complete the setup, you need to call the API and trigger a message. If you’re not yet ready to send a message directly from your code, you can use an HTTP client like Postman or send a cURL request from your terminal to test your message and complete the setup process.
Examples and API parameters
Below are examples of transactional emails. We’ve provided a basic payload and examples for cURL, our Node.JS SDK, and our Python SDK.
We’ve also provided a list of parameters for transactional message payloads. Your payload changes based on whether you reference a transactional_message_id
(a template) or not. See our REST API documentation for more information.
{
"transactional_message_id": 44,
"to": "cool.person@example.com",
"subject": "Did you really login from a new location?",
"identifiers": {
"email": "cool.person@example.com"
},
"message_data": {
"password_reset_token": "abcde-12345-fghij-d888",
"account_id": "123dj"
},
"send_to_unsubscribed": true,
"tracked": true,
"disable_css_preprocessing": true
}
const { APIClient, SendPushRequest, RegionUS } = require("customerio-node");
const api = new APIClient('app-key', { region: RegionUS });
const request = new SendPushRequest({
to: "person@example.com",
transactional_message_id: "44",
message_data: {
password_reset_token: "abcde-12345-fghij-d888",
account_id: "123dj"
},
identifiers: {
id: "2",
},
});
api.sendPush(request)
.then(res => console.log(res))
.catch(err => console.log(err.statusCode, err.message))
from customerio import APIClient, Regions, SendPushRequest
client = APIClient("your API key", region=Regions.US)
request = SendPushRequest(
transactional_message_id="3",
identifiers={
"id": "2",
}
)
response = client.send_push(request)
print(response)
curl --request POST \
--url https://api.customer.io/v1/send/email \
--header 'content-type: application/json' \
--data '{
"transactional_message_id": 44,
"to": "cool.person@example.com",
"from": "override-templated-address@example.com",
"subject": "Did you really login from a new location?",
"identifiers": {
"email": "cool.person@example.com"
},
"message_data": {
"password_reset_token": "abcde-12345-fghij-d888",
"account_id": "123dj"
},
"bcc": "bcc@example.com",
"disable_message_retention": false,
"send_to_unsubscribed": true,
"tracked": true,
"queue_draft": false,
"disable_css_preprocessing": true
}'
- transactional_message_idRequired The transactional message template that you want to use for your message. You can call the template by its numerical ID or by the Trigger Name that you assigned the template (case insensitive).integerThe ID of the transactional message you want to send.
- body stringThe HTML body of your message. This overrides the body of the transactional template (referenced by
transactional_message_id
). If you send an AMP-enabled email (withbody_amp
), and the recipient’s email client doesn’t support AMP, this is the fallback email. - body_amp stringIf your message is an email, this is the AMP-enabled body of your message. If your recipient’s email client doesn’t support AMP, the
body
represents your fallback message. - body_plain stringThe plaintext body of your message. This overrides the body of your transactional template (referenced by
transactional_message_id
). - from stringThe address that your email is from. This address must be verified by Customer.io. This overrides the from address set within the transactional template (referenced by
transactional_message_id
). You can include a display/friendly name in your from address, but we recommend that you use quotation marks around the friendly name to avoid potential issues with special characters, e.g.\"Person\" <person@example.com>
. - language stringOverrides language preferences for the person you want to send your transactional message to. Use one of our supported two- or four-letter language codes.
- subject stringThe subject line for your message. This overrides the subject of the transactional template (referenced by
transactional_message_id
). - disable_message_retention booleanIf true, the message body is not retained in delivery history. Setting this value overrides the value set in the settings of your
transactional_message_id
. - identifiersRequired Identifies the person represented by your transactional message by one of, and only one of,
id
,email
, orcio_id
.- id stringRequired The identifier for the person represented by the transactional message. NOTE: If your workspace identifies people by email, use the
email
identifier instead.
-
- Liquid Data* any typeInsert key-values that you want to reference in your message here.
- queue_draft booleanIf true, your transactional message is held as a draft in Customer.io and not sent directly to your audience. You must go to the Deliveries and Drafts page to send your message.
- send_at integerA unix timestamp (seconds since epoch) determining when the message will be sent. The timestamp can be up to 90 days in the future. If this value is in the past, your message is sent immediately.
- send_to_unsubscribed boolean
Default:
If false, your message is not sent to unsubscribed recipients. Setting this value overrides the value set in the settings of yourtrue
transactional_message_id
. - attachments array of [ objects ]A dictionary of attachments where the filename is the key and the value is the base64-encoded contents. The total size of all attachments must be less than 2 MB. Some filetype extensions are restricted.
- bcc stringBlind copy message recipients. Supports multiple addresses separated by commas. Your request can contain up to 15 total recipients between the
to
andbcc
keys. - body_plain stringBy default, we generate a plaintext version of your message body for each delivery. Use this key to override the default plain text body.
- disable_css_preprocessing booleanSet to
true
to disable CSS preprocessing. This setting overrides the CSS preprocessing setting on thetransactional_message_id
as set in the user interface. Transactional emails have CSS preprocessing enabled by default. - fake_bcc booleanIf true, rather than sending true copies to BCC addresses, Customer.io sends a copy of the message with the subject line containing the recipient address(es).
-
- name stringname of header
- value stringvalue of header
- preheader stringAlso known as “preview text”, this is the block block of text that users see next to, or underneath, the subject line in their inbox.
- reply_to stringThe address that recipients can reply to, if different from the
from
address. - to string
The message recipient(s). Supports multiple addresses separated by commas. Your request can contain up to 15 total recipients between the
to
andbcc
keys.You can include a display or “friendly” name in “to” address, but we recommend that you use quotation marks around the friendly name to avoid potential issues with special characters, e.g.
\"Person\" <person@example.com>
. - tracked boolean
Default:
If true, Customer.io tracks opens and link clicks in your message.true
Update the content of your email
You can update the contents of your message through our user interface or API.
We’ve exposed an API endpoint so you can manage your message contents programmatically. This request takes a body
, which represents the complete HTML content of your message.
You’ll reference the message you want to update by transactional_id
and content_id
. You can find both in the URL when you look at the content of a message in the format https://fly.customer.io/journeys/env/last/composer/transactional/:transactional_message_id/templates/:content_id
. For example, if I look at a transactional message with this URL: https://fly.customer.io/journeys/env/last/composer/transactional/3/templates/139
, then the transactional_id
is 3 and the content_id
is 139.
curl --request PUT \
--url https://api.customer.io/v1/transactional/{transactional_id}/content/{content_id} \
--header 'Authorization: Bearer REPLACE_BEARER_TOKEN' \
--header 'content-type: application/json' \
--data '{"body":"string"}'
It can take a few minutes for us to process changes to your snippet.
This means your customers may receive outdated content if, for instance, your campaign is active, you update a snippet in an email, then 30 seconds later we send that email. This could also happen if the message is at the beginning of your workflow, you update a snippet in the message, then immediately activate a campaign or trigger a broadcast, newsletter, or transactional message that contains it.