Domain
Returns everything after the first at sign of an email address. Runtime-proven on a live Marketing Cloud Engagement CloudPage — including multi-level domains, which come back whole rather than reduced, and the original casing, which is preserved.
Syntax
Domain(emailAddress) → string
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
emailAddress |
string | Yes | Email address; the text after the first at sign is returned verbatim |
Example
%%[ VAR @d SET @d = Domain("tomas.q@example.com") ]%%
%%=v(@d)=%%
Renders example.com.
Routing on the domain means folding the case first, because the result keeps whatever casing the address had:
%%[
VAR @d
SET @d = Lowercase(Domain(emailaddr))
]%%
%%=IIf(@d == "example.com", "internal recipient", "external recipient")=%%
Return value
string — the text following the first at sign.
There is no closed set of sentinel values to test for. An input with no at sign, an empty string, a bare at sign, an at sign with nothing after it and a number all render nothing at all; the docs describe those cases as a null return, and on a page that is an empty value. Use Empty to detect it rather than comparing against a literal.
Behaviour
The split is on the first at sign, and the rest is returned verbatim. Domain("a@b@example.com") gives b@example.com — the second at sign is part of the result, not a reason to fail.
A multi-level domain comes back whole. Domain("tomas.q@a.b.example.co.uk") gives a.b.example.co.uk, and a five-label domain returns all five labels. Nothing is reduced to a registrable domain.
The original casing is preserved. Domain("Tomas.Q@Example.COM") gives Example.COM, so a comparison against a lowercase allow-list needs Lowercase around it.
No validation happens. Values that IsEmailAddress rejects still produce a domain: Domain("tomas q@example.com") gives example.com and Domain("hello@world") gives world. Validate first if that matters.
A plus tag in the local part changes nothing. Domain("tomas.q+news@example.com") gives example.com.
What comes back for each shape
| Call | Renders |
|---|---|
Domain("tomas.q@example.com") |
example.com |
Domain("tomas.q+news@example.com") |
example.com |
Domain("tomas.q@a.b.example.co.uk") |
a.b.example.co.uk |
Domain("a@b@example.com") |
b@example.com |
Domain("Tomas.Q@Example.COM") |
Example.COM |
Domain("hello@world") |
world |
Domain("example.com") |
(empty) |
Domain("tomas.q@") |
(empty) |
Domain("@") |
(empty) |
Domain("") |
(empty) |
Domain(123) |
(empty) |
Show test script
%%[
VAR @b
SET @b = RequestParameter("b")
/* known-good control: renders on every request, so a run of HTTP 422s
can be told apart from a broken deploy */
OutputLine(Concat("CTRL=[", Uppercase("ok"), "]"))
/* what is extracted, for the shapes a caller actually meets */
OutputLine(Concat("--- D start ---"))
OutputLine(Concat("D1_plain=[", Domain("tomas.q@example.com"), "]"))
OutputLine(Concat("D2_no_at=[", Domain("example.com"), "]"))
OutputLine(Concat("D3_multilevel=[", Domain("tomas.q@a.b.example.co.uk"), "]"))
OutputLine(Concat("D4_double_at=[", Domain("a@b@example.com"), "]"))
OutputLine(Concat("D5_plustag=[", Domain("tomas.q+news@example.com"), "]"))
OutputLine(Concat("D6_upper=[", Domain("Tomas.Q@Example.COM"), "]"))
OutputLine(Concat("--- D done ---"))
/* the empty string, in its own branch: the sibling IsCHTMLBrowser aborts
on it, so the four functions must not share one empty-string branch */
IF @b == "d_empty" THEN
OutputLine(Concat("--- d_empty start ---"))
OutputLine(Concat("D_EMPTY=[", Domain(""), "]"))
OutputLine(Concat("--- d_empty done ---"))
ENDIF
/* degenerate at-sign placements and a value no validator would accept */
IF @b == "d_edge" THEN
OutputLine(Concat("--- d_edge start ---"))
OutputLine(Concat("D_AT_ONLY=[", Domain("@"), "]"))
OutputLine(Concat("D_TRAIL_AT=[", Domain("tomas.q@"), "]"))
OutputLine(Concat("D_SPACE=[", Domain("tomas q@example.com"), "]"))
OutputLine(Concat("D_NOT_EMAIL=[", Domain("hello@world"), "]"))
OutputLine(Concat("D_MULTI2=[", Domain("x@sub.a.b.example.co.uk"), "]"))
OutputLine(Concat("--- d_edge done ---"))
ENDIF
/* a non-string argument */
IF @b == "g_num" THEN
OutputLine(Concat("--- g_num start ---"))
OutputLine(Concat("D_NUM=[", Domain(123), "]"))
OutputLine(Concat("--- g_num done ---"))
ENDIF
/* the empty result confirmed with a second function rather than read off
a blank pair of brackets */
IF @b == "g_tok" THEN
OutputLine(Concat("--- g_tok start ---"))
OutputLine(Concat("D_NULLCHK=[", IIf(Empty(Domain("example.com")), "domain-empty", "domain-not-empty"), "]"))
OutputLine(Concat("--- g_tok done ---"))
ENDIF
]%%
Every marker and label in the test script goes through Concat(...), including single-argument ones. A bare string literal passed to OutputLine renders an empty line while the page still returns HTTP 200, so the marker silently vanishes.
Availability
| Platform | Available |
|---|---|
| Marketing Cloud Engagement | Yes |
| Marketing Cloud Next | No |
See also
- IsEmailAddress — validate the address before splitting it, since this function will not
- Empty — how to detect the empty result
- Official reference · ampscript.guide