Skip to main content

Validation functions — Marketing Cloud AMPscript reference

AMPscript's validation surface — Empty / IsNull / IsEmailAddress / IsPhoneNumber / IsNumeric. Useful for render-time branching, dangerous as a substitute for upstream data quality. The patterns that survive at scale.

Reference·Last updated 2026-05-13·Drafted by Lira · Edited by German Medina

AMPscript ships a small set of validation helpers — Empty, IsNull, IsEmailAddress, IsPhoneNumber, IsNumeric. They're built for render-time branching: deciding whether to fall back to a default greeting, whether to show or hide a content block, whether to skip a CTA when the data isn't there. They are not built to be the validation layer for incoming data — that work belongs in the SQL Activity that shapes the audience DE, where you can reject bad rows before the send even runs.

The list below is the surface plus the failure modes for treating these as a substitute for upstream validation.

Official syntax

%%[
  /* NULL / empty checks */
  SET @firstName = AttributeValue("FirstName")
  IF Empty(@firstName) THEN
    SET @firstName = "Friend"
  ENDIF

  /* Format validation */
  IF IsEmailAddress(@altEmail) THEN
    /* @altEmail looks like a valid email by AMPscript's lax check */
  ENDIF

  IF IsPhoneNumber(@phone) THEN
    /* @phone looks like a US phone by AMPscript's pattern */
  ENDIF

  IF IsNumeric(@scoreStr) THEN
    /* @scoreStr can be passed to Add/Multiply without coercing to 0 */
    SET @score = Add(@scoreStr, 0)
  ELSE
    SET @score = 0
  ENDIF

  /* Existence check via length — useful when Empty isn't expressive enough */
  IF Length(Trim(@input)) > 0 THEN
    /* Non-whitespace content present */
  ENDIF
]%%

The supported set:

| Function | Returns true when | Notes | |---|---|---| | Empty(v) | v is NULL, empty string, or unset variable | The broadest check — covers everything | | IsNull(v) | v is NULL only | Empty string is false | | IsEmailAddress(s) | s matches a regex roughly compatible with RFC 5321 | No DNS check; accepts addresses real mail servers reject | | IsPhoneNumber(s) | s matches a US phone pattern (10 digits, common separators) | US-biased; won't validate international | | IsNumeric(s) | s parses as a number | Allows leading sign, decimal point; rejects formatting like commas or currency | | IsCHQ(s) | Less common; checks Canadian/US zip patterns | Niche; rarely used in practice |

Reference:

What survives in production

Empty vs IsNull vs == "" — pick one, document why

The three concepts:

  • Empty(@x) — true for NULL, empty string, or unset variable. The broadest check.
  • IsNull(@x) — true only for NULL. Empty string is false.
  • @x == "" — true only for empty string after AMPscript's loose-typed comparison.
%%[
  /* @x might be NULL, "", a string, or never SET */

  IF Empty(@x) THEN
    /* Fires for all three "nothing" shapes — the durable default */
  ENDIF

  IF IsNull(@x) THEN
    /* Fires only when @x is literally NULL — leaves "" through */
  ENDIF

  IF @x == "" THEN
    /* Fires only when @x is the empty string — leaves NULL through */
  ENDIF
]%%

Empty is the default for personalization fallback. Reach for IsNull only when you specifically need to distinguish a never-set value from a deliberately-empty one (rare). Avoid == "" for emptiness — it doesn't cover NULL, and the next person inheriting the code will assume it does. See gotchas — #8.

IsEmailAddress is liberal — it's a regex match, not a delivery check

IsEmailAddress("ana@example") returns true. So does "ana@local.123". The function matches the broad RFC-5321 pattern: at least one character, an @, at least one character with a dot somewhere. It doesn't:

  • Resolve DNS — ana@made-up-tld.example passes
  • Reject single-label hostnames — ana@localhost passes
  • Check character escaping rules deeply — ana"smith"@example.com may pass or fail depending on tenant
%%[
  /* This passes IsEmailAddress, will fail at the MTA */
  IF IsEmailAddress("test@invalid") THEN
    /* DON'T trust this as "ready to send" */
  ENDIF

  /* For real delivery confidence, validate upstream */
  /* SQL Activity: 
       WHERE EmailAddress LIKE '%@%.%' 
         AND EmailAddress NOT LIKE '%@localhost%' 
         AND CharIndex(' ', EmailAddress) = 0
     ...and even then, the only true validation is "the MTA didn't bounce it" */
]%%

The Cleon rule: IsEmailAddress is for render-time branching ("if the alt-email is shaped like an email, show this block"). It is not for deciding whether to send. The Send Activity itself does basic shape validation; the audience DE's row should already be trusted by the time AMPscript runs.

IsPhoneNumber is US-biased

IsPhoneNumber("212-555-0100") returns true. IsPhoneNumber("+54 11 4444-5555") returns... it depends on the tenant. AMPscript's pattern is closer to "10 digits with common US separators" than a true international phone validator.

%%[
  IF IsPhoneNumber(@phone) THEN
    /* Confidence for US numbers; uncertain for international */
  ENDIF

  /* For multi-region audiences, validate via a stricter pattern
     upstream in SQL using LIKE / RegEx, or check against a
     pre-normalized E.164 column. */
]%%

If your audience is global, do not rely on IsPhoneNumber for any logic that affects deliverability. Pre-validate to E.164 format upstream (SQL Activity or an SSJS callout to a normalization service) and trust the column.

IsNumeric is the cleanest defense against silent coercion

The string-to-number coercion in math functions is the gateway to bugs: Add("abc", 5) returns 5. IsNumeric is the gate before the math:

%%[
  SET @raw = AttributeValue("LoyaltyPoints")

  IF IsNumeric(@raw) THEN
    SET @points = Add(@raw, 0)
  ELSE
    SET @points = 0
  ENDIF

  /* @points is now safely numeric — math downstream is trustworthy */
]%%

The gotcha-of-the-gotcha: IsNumeric("1,000") returns false in most tenants because the comma fails the parse. If your source has formatted numbers (currency strings, comma-separated thousands), strip the formatting with Replace before testing.

%%[
  SET @clean = Replace(Replace(@raw, "$", ""), ",", "")
  IF IsNumeric(@clean) THEN
    SET @value = Add(@clean, 0)
  ELSE
    SET @value = 0
  ENDIF
]%%

Length(Trim(@x)) > 0 is the "real content" check

Empty(@x) is true for NULL and "". But it's false for a string of pure whitespace — " " is not empty by AMPscript's lights. For "the recipient actually wrote something" checks (CloudPage form input, free-text fields), use the trim+length idiom:

%%[
  SET @comment = RequestParameter("comment")

  /* AT RISK — "    " (just spaces) passes Empty */
  IF NOT Empty(@comment) THEN
    /* @comment might be all whitespace */
  ENDIF

  /* DURABLE — real content check */
  IF Length(Trim(@comment)) > 0 THEN
    /* @comment has non-whitespace content */
  ENDIF
]%%

The hand-off failure: someone tests with @comment = "valid input" (renders a thank-you block) and @comment = "" (renders a fallback). They miss @comment = " " because they didn't think a user would submit spaces. A web form does submit them — paste artifacts, accidental autofill, intentional spammers — and the email renders the thank-you block for empty input.

Validation in AMPscript is render-time, not pre-flight

The deeper failure shape: AMPscript validation functions encourage thinking "I'll validate at render time." Don't. By the time AMPscript runs, the recipient is already in the audience, the Send Activity has already accepted the row, and any "this row shouldn't have been sent to" decision is too late.

The right place for data validation is the SQL Activity that builds the audience DE:

-- Upstream: reject rows that don't meet the validation bar
SELECT *
INTO de_send_audience_<name>
FROM master_subscribers
WHERE EmailAddress LIKE '%@%.%'
  AND EmailAddress NOT LIKE '%@localhost%'
  AND CharIndex(' ', EmailAddress) = 0
  AND Status = 'Active'
  AND Empty(EmailAddress) = 0; /* SQL Activity has its own Empty */

AMPscript's job is to render gracefully when a column is missing or shaped wrong despite upstream validation, not to be the validation layer. Treating AMPscript validation as the bar is how rows with malformed emails reach the MTA and bounce.

Quick decision

Use Empty when:

  • Defaulting a personalization variable to a fallback. The broadest check covers NULL, empty string, and unset.

Use IsNull when:

  • You specifically need to distinguish "never set" from "deliberately empty". Rare in personalization; more common in CloudPage form processing.

Use IsEmailAddress / IsPhoneNumber when:

  • Branching the email based on the shape of an alt-contact field. Don't trust as a gate against bad deliveries — that gate is upstream.

Use IsNumeric when:

  • About to pass a string into a math function. Strip currency/comma formatting first with Replace.

Use Length(Trim(@x)) > 0 when:

  • Checking for real content in a free-text field. Whitespace-only strings pass Empty().

Move validation to SQL upstream when:

  • The check decides whether to send. AMPscript runs after the audience is built; SQL runs before.
  • The pattern is non-trivial (regex, multi-column rules, cross-DE checks). SQL has the full surface; AMPscript's is lax.
  • The same validation applies to every recipient on a large send. One SQL pass beats 50k AMPscript evaluations.

Related

  • Basics — supported language surface
  • Math functions — the silent coercion that IsNumeric is built to gate
  • String functionsLength, Trim, Replace for content checks and pre-validation cleanup
  • MC AMPscript gotchas — see #8 (Empty vs IsNull vs == "") and #10 (silent Cloud-write failures, where validation matters most)
  • MC SQL — String functions — the upstream pattern matching that should reject bad rows before they reach the audience

More AMPscript reference pages incoming: Data Extension · Subscriber/Profile · Cloud-write · Encoding/Hashing · Style Guide.