AMPscript in Marketing Cloud: fallbacks, templates and SAP

An AMPscript guide for Marketing Cloud: a first name that never prints blank, Content Builder template slots, email limits, and SAP with DKIM and DMARC.

250,000

Emails a month above which Salesforce says Marketing Cloud senders must use the Sender Authentication Package
On this page
  1. Personalization strings or AMPscript?
  2. How do I give a first name a fallback in AMPscript?
  3. Does the fallback work in the subject line and preheader?
  4. How do I test personalization before sending?
  5. How do Lookup, Concat, FormatDate and Replace work?
  6. How do I create an email template in Content Builder?
  7. What are Marketing Cloud's email limits?
  8. What does the Sender Authentication Package include?
  9. Which DNS records does Marketing Cloud need?
  10. Does Marketing Cloud's DKIM align with my From domain?
  11. How do I check authentication once it is live?
  12. Sources

AMPscript is the scripting language of Salesforce Marketing Cloud Engagement. Code between %%[ and ]%% runs when the email is sent, and %%= and =%% print a value inline (Salesforce). For a first name that never prints blank, read the field with AttributeValue(), test it with Empty() and print a fallback with v(), because a plain personalization string appears blank when the attribute is empty.

This guide covers Marketing Cloud Engagement (Email Studio and Content Builder), not Account Engagement, formerly Pardot: the AMPscript an email builder needs, Content Builder templates, the documented limits, and the Sender Authentication Package.

Personalization strings or AMPscript?

A personalization string is an attribute name between double percent signs, such as %%First_Name%%. Strings work in the subject line, preheader and body, are case-insensitive, and appear blank when the attribute is empty. Salesforce's advice is to define a default for every attribute you use this way.

Two names catch people out. %%firstname%% is a system string that returns the word before the first space in the Full Name profile attribute, and Full Name, Email and UserDefined are the only profile attributes an account starts with. Salesforce's list of strings says not to use any of them as a column name in a sendable data extension, so call the column First_Name, as Salesforce's own example does, not FirstName.

The rest of the syntax, from Adding AMPscript to Your Content and Variables:

You writeWhat it is
%%First_Name%%A personalization string. Prints the attribute or column, or nothing when it is empty.
%%firstname%%A system string: the first word of the Full Name profile attribute.
%%[ ... ]%%An AMPscript block. Declares variables and runs several functions.
%%= ... =%%Inline AMPscript. One function, which may nest others, and prints its result.
<script runat="server" language="ampscript">The tag form of a block, written the way server-side JavaScript is.
@firstNameA variable. Names always begin with the at sign.

How do I give a first name a fallback in AMPscript?

Salesforce's help page gives this pattern, with "Customer" as the fallback:

%%[IF Empty(First_Name) == "False" THEN SET @FN = First_Name ELSE SET @FN = "Customer" ENDIF]%%Hi %%=v(@FN)=%%

It assumes First_Name exists in the data you send to. The developer reference prefers AttributeValue(), which searches the subscriber profile, the sendable data extension and journey data, and returns null when it finds nothing instead of failing the send. With the reference's Iif() greeting:

%%[
  Var @firstName, @greeting
  Set @firstName = Trim(AttributeValue("First_Name"))
  Set @greeting = Iif(Empty(@firstName), "Hi there,",
    Concat("Hi ", @firstName, ","))
]%%
<p>%%=v(@greeting)=%%</p>

Line by line:

When the name lives in another data extension, use Lookup(). It returns the first matching row, and the search column and value are case-sensitive, so match on a unique key. With sample names:

%%[
  Var @owner
  Set @owner = Lookup("Account_Owners", "Owner_First_Name", "Account_ID", AttributeValue("Account_ID"))
  If Empty(@owner) Then
    Set @owner = "your account team"
  EndIf
]%%

Without code, a profile attribute can carry a default value for every subscriber who has none. Salesforce's page does not say it covers a data extension column of the same name.

Does the fallback work in the subject line and preheader?

Yes, with a catch. AMPscript runs in a fixed order: preheader, HTML body, text body, then subject line. A variable set in the HTML body keeps its value in the text body and subject line, but the preheader has already run:

  1. Preheader

    Runs first, before the block has set anything

    %%=v(@greeting)=%% here are Tuesday's notes
    First_Name is Ada

    (nothing) here are Tuesday's notes

    First_Name is empty

    (nothing) here are Tuesday's notes

  2. HTML body

    Runs second. The block sets @greeting here

    %%[ ...
      Set @greeting = Iif(Empty(@firstName),
        "Hi there,",
        Concat("Hi ", @firstName, ","))
    ]%%
    <p>%%=v(@greeting)=%%</p>
    First_Name is Ada

    Hi Ada,

    First_Name is empty

    Hi there,

  3. Text body

    Runs third, with the value the HTML body set

    %%=v(@greeting)=%%
    First_Name is Ada

    Hi Ada,

    First_Name is empty

    Hi there,

  4. Subject line

    Runs last, with the same value

    %%=v(@greeting)=%% your notes from Tuesday
    First_Name is Ada

    Hi Ada, your notes from Tuesday

    First_Name is empty

    Hi there, your notes from Tuesday

Orange: the part that runs before the variable existsDashed: the greeting prints nothing

Example. One greeting set in the HTML body and printed in all four parts of the message, for a subscriber with a first name and one without. Run order from Salesforce's Order of Operations; the greeting is its Iif() example with the name read through AttributeValue(). Read 31 October 2026.

So a subject line can reuse %%=v(@greeting)=%%, while a preheader that greets by name needs its own inline Iif().

In links, Salesforce asks you not to include personal data such as an email address. For a URL built from data, write the <a> tag in the email and put RedirectTo() in its href, which is how Salesforce says click tracking is kept:

<a href='%%=RedirectTo(@link)=%%'>%%=v(@type)=%%</a>

Note

As of October 2026, Salesforce marks AttributeValue() and RedirectTo() as unavailable in Marketing Cloud Next.

How do I test personalization before sending?

Preview and Test renders the email with one subscriber's data and sends tests only to the addresses you enter. A data extension can be previewed if it has an email address field or links to subscribers by ID or key. Three cautions from the same page: a test send counts against the sends you bought, attribute changes made during preview are permanent, and a test to an unsubscribed, bounced or held subscriber never arrives.

Test with a row for each case the code handles: a normal name, an empty field, a single space, and an account missing from the lookup table.

How do Lookup, Concat, FormatDate and Replace work?

Syntax copied from Salesforce's reference:

FunctionSyntaxWhat to know
LookupLookup(dataObject, returnColumn, searchColumn1, searchValue1, [searchColumn2, searchValue2...])Returns the first match. Add column and value pairs to narrow it.
ConcatConcat(string1, string2, [string3], ...)Takes as many strings as you pass.
FormatDateFormatDate(dateString, dateFormat, timeFormat, localeCode)Uses .NET format strings in Engagement: "d MMMM yyyy" gives 5 August 2023.
ReplaceReplace(sourceString, searchSubstring, replacementSubstring)Replaces every occurrence, not just the first.

FormatDate matters for one more reason: date strings such as %%xtlongdate%% print in US format.

How do I create an email template in Content Builder?

Content Builder makes a template from pasted HTML or an existing template, and both open in the same editor. A region is editable when it is a content area: a div with data-type="slot". Salesforce's example (Add Content to a Paste HTML Template) allows one block of five types and sets the hint shown while the area is empty:

<div data-type="slot" data-key="Hero1" data-max-blocks="1" data-allowed-blocks="imageblock; textblock; freeformblock; abtestblock; dynamicblock" data-label="Place Hero Image Here"></div>
<body>
<!-- the Track Email Opens snippet -->

Open tracking

Inserted from Insert Code Snippet, immediately after the opening body tag.

<custom type="header" />

Account header

Where the account's header goes. Only paste HTML templates take this tag.

<table role="presentation" width="600">
  <tr><td><img src="logo.png" alt="Logo"></td></tr>
</table>

Fixed HTML

Outside any content area. Code View is locked in an email made from the template, so this stays as written.

<div data-type="slot" data-key="hero"
  data-max-blocks="1" data-allowed-blocks="imageblock"
  data-label="Hero image here"></div>

Content area, restricted

One block, images only. The label is the hint shown while the area is empty.

<div data-type="slot" data-key="main"
  data-label="Drop blocks or content here"></div>

Content area, open

Any number of blocks of any type, the default.

<custom type="footer" />

Account footer

The standard footer carries the profile center link, the unsubscribe link and the postal address.

</body>

Orange: the attribute that makes a region editable

Example. A paste HTML template in Content Builder, with each region beside what makes it so. Syntax from Salesforce's Add Content to a Paste HTML Template and Content Builder Editor Best Practices and Tips, read 31 October 2026. The keys, labels and logo row are made up.

The rules for content areas, from the same two pages:

  • Keys. Alphanumeric, under 17 characters, no spaces or capitals, though Salesforce's own Hero1 has one. Reserved words such as content, name, design and tags can make a template unusable once saved.
  • Locking. A filled area can be locked so emails made from the template cannot change it.
  • No cascade. Editing a template does not change emails already made from it.

Where Content Builder changes your HTML

HTML content blocks can add extra code wrappers, so Salesforce recommends code snippets for code that must stay exact. ContentBlockByKey() and its siblings also pull in the table the editor wraps around a block, which a code snippet avoids. In an email made from a template, Code View is locked.

What every template has to include

A paste HTML template carries what the account would otherwise add: <custom type="header" /> and <custom type="footer" /> where those belong, and the open-tracking snippet right after the opening <body> tag. Every email must include a profile center link, an unsubscribe link and your business address:

%%profile_center_url%%
%%unsub_center_url%%
%%Member_Busname%%
%%Member_Addr%%
%%Member_City%%
%%Member_State%%
%%Member_PostalCode%%
%%Member_Country%%

The standard footer holds them; text-only emails need them added by hand. Setup, Email Optional Features can switch the checks off, but Salesforce says you stay responsible for the legally required content.

What are Marketing Cloud's email limits?

From Salesforce's Email Limits and Guidelines, as of October 2026:

LimitValue
Sending on shared IP addresses250,000 emails a month. Above that Salesforce requires dedicated IPs, though it does not throttle
One dedicated IP address2 million emails a day, a guideline for a warmed-up address
Warming up a new dedicated IP31 days
Attachment size5 MB
Message body100 KB or less, so webmail clients do not truncate it
Email archive retention21 days
Unsent triggered messagesExpire after 3 days in the queue

The body figure is a tip, and it sits close to the size at which Gmail clips a message. The page sets no template width.

What does the Sender Authentication Package include?

The Sender Authentication Package (SAP) puts your domain on everything a message carries: account branding for tracked links, images and the view-as-webpage link; a private domain for the From address, authenticated with SPF, Sender ID and DKIM; CloudPages domains; a dedicated IP address; and Reply Mail Management. Senders of more than 250,000 emails a month must use it. Corporate and Pro editions include one SAP license, and Enterprise five.

A Private Domain on its own is the authentication part: DKIM, SPF and DMARC for the sending domain, without link branding or a dedicated IP, which Salesforce says suits any volume.

To set either up, as of October 2026 (Salesforce):

  1. In Setup, type ssl in Quick Find, open Domain SSL Certificates and click New Domain.
  2. Enter the domain and an address for DNS and certificate notices.
  3. Choose email authentication and URL branding (SAP) or email authentication only (Private Domain).
  4. Choose the shared IP pool (under 100,000 emails a month), a new dedicated IP (over 250,000) or one you have, and whether to use Reply Mail Management.
  5. Choose how to manage DNS, then submit.

The status moves from Pending DNS validation to In progress, which can take up to five business days, to Active.

Which DNS records does Marketing Cloud need?

Either delegate the domain or a subdomain to Salesforce, which takes four NS records, ns1.exacttarget.com through ns4.exacttarget.com, or host DNS yourself and apply the zone file you download from the domain's action menu. Salesforce's sample zone for a sending domain of sample.example.com:

HostTypeWhat it does
sample.example.comMXLets Marketing Cloud's servers send
bounce.sample.example.comMX and TXTHandles bounces, with its own SPF record
reply.sample.example.comMX and TXTReply Mail Management, with its own SPF record
leave.sample.example.comMXUnsubscribes
image, view, click, pages, cloudCNAMEImages, view as web page, tracked clicks, landing pages, CloudPages
mta.sample.example.comAThe dedicated IP address
example._domainkey.sample.example.comTXTThe DKIM key, under the selector example
sample.example.comTXTSPF, authorizing the bounce host
_dmarc.sample.example.comTXTDMARC

The sample selector is a placeholder; your zone file carries the real one. Hyperforce accounts get their entries later in setup instead.

Does Marketing Cloud's DKIM align with my From domain?

Yes, when the From address uses the SAP or private domain. Salesforce's Gmail compliance FAQ says SPF, DKIM and DMARC then typically pass, on self-hosted DNS once its TXT records are in place. Its troubleshooting article adds that sending from a domain not set up as SAP or a private domain fails authentication by default.

The sample zone shows why it aligns: the DKIM key sits under the sending domain, so the signing domain is yours, and the bounce host is its subdomain, so SPF aligns under DMARC's relaxed rule too (how alignment works).

On a delegated domain, Salesforce Support edits the DMARC record, including a rua address for reports, when you send them the record you want. Commercial sends get a List-Unsubscribe header automatically, which the bulk sender rules expect. Your main website domain can be the private domain, but then you host its records, and Support does not troubleshoot self-hosted DNS.

How do I check authentication once it is live?

Send tests to Gmail and Outlook.com, not only to your own company. Salesforce's troubleshooting article explains that corporate security gateways scan bodies and rewrite links, which breaks a DKIM signature even when the setup is right, so a failure seen only at corporate domains is usually not Marketing Cloud's. Then read the Authentication-Results line in a test's full header (Show original, in Gmail).

The free editor exports HTML with personalization strings, an inline Iif() fallback and %%unsub_center_url%% written in. Before the copy goes into Marketing Cloud, draft it in the free mail-merge preview, which shows each message against a sample of your list and flags every empty merge field, and run the email domain checker on your sending domain. Draftship also builds and runs outbound inside a client's own platform.

Sources

  • developer.salesforce.comCode between %%[ and ]%% runs when the email is sent, and %%= and =%% print a value inline
  • help.salesforce.comappears blank when the attribute is empty
  • help.salesforce.comthe word before the first space in the Full Name profile attribute
  • help.salesforce.comonly profile attributes an account starts with
  • developer.salesforce.comThe rest of the syntax, from Adding AMPscript to Your Content and Variables
  • developer.salesforce.comThe developer reference prefers AttributeValue(), which searches the subscriber profile, the sendable data extension and journey data, and returns null when it finds nothing instead of failing the send
  • developer.salesforce.comWith the reference's Iif() greeting
  • developer.salesforce.comstrips white space from both ends
  • developer.salesforce.comTrim() strips white space from both ends, because Empty() is true only for an empty string or null, and a field holding one space would print Hi
  • developer.salesforce.comspaces have to be written in
  • developer.salesforce.comv() prints the variable
  • developer.salesforce.comWhen the name lives in another data extension, use Lookup()
  • help.salesforce.comWithout code, a profile attribute can carry a default value for every subscriber who has none
  • developer.salesforce.compreheader, HTML body, text body, then subject line
  • developer.salesforce.comFor a URL built from data, write the <a> tag in the email and put RedirectTo() in its href, which is how Salesforce says click tracking is kept
  • help.salesforce.comrenders the email with one subscriber's data
  • developer.salesforce.comFormatDate(dateString, dateFormat, timeFormat, localeCode). Uses .NET format strings in Engagement: "d MMMM yyyy" gives 5 August 2023.
  • developer.salesforce.comReplace(sourceString, searchSubstring, replacementSubstring). Replaces every occurrence, not just the first.
  • help.salesforce.comopen in the same editor
  • help.salesforce.comAdd Content to a Paste HTML Template
  • developer.salesforce.comContentBlockByKey() and its siblings also pull in the table the editor wraps around a block, which a code snippet avoids
  • help.salesforce.comEvery email must include a profile center link, an unsubscribe link and your business address
  • help.salesforce.comEmail Limits and Guidelines
  • help.salesforce.comThe Sender Authentication Package (SAP) puts your domain on everything a message carries: account branding for tracked links, images and the view-as-webpage link; a private domain for the From address, authenticated with SPF, Sender ID and
  • help.salesforce.comA Private Domain on its own is the authentication part: DKIM, SPF and DMARC for the sending domain, without link branding or a dedicated IP, which Salesforce says suits any volume
  • help.salesforce.comTo set either up, as of October 2026
  • help.salesforce.comSalesforce's sample zone for a sending domain of sample.example.com
  • help.salesforce.comSalesforce's Gmail compliance FAQ says SPF, DKIM and DMARC then typically pass, on self-hosted DNS once its TXT records are in place
  • help.salesforce.comIts troubleshooting article adds that sending from a domain not set up as SAP or a private domain fails authentication by default
  • support.google.comThen read the Authentication-Results line in a test's full header (Show original, in Gmail)

Who do you want to hear back from?

Tell us who you sell to and what you have tried. We'll get back to you ASAP, and if it looks like a fit, we build it into your systems within days.

Or write to hello@draftship.io