Runtime verified Test scripts included

Syntax

MD5(stringToConvert[, charSet])  →  string
1–2 arguments

Parameters

Name Type Required Description
stringToConvert string | number | date Yes The value to hash; a number or date is hashed as the text it renders as
charSet string No Name of the character encoding applied before hashing; defaults to UTF-8

Example

%%[
  VAR @digest
  SET @digest = MD5("Hash probe 2026")
]%%
%%=v(@digest)=%%

Renders 2bfdbd320b3b56c0d8c4be16462a96b7.

The usual reason to reach for a hash is a stable, non-reversible key for a value you do not want to put in a URL:

%%[
  VAR @email, @token
  SET @email = "reader@example.org"
  SET @token = MD5(Lowercase(Trim(@email)))
]%%
<a href="https://example.org/prefs?id=%%=v(@token)=%%">Manage preferences</a>

Normalise before hashing, as above — a digest of a differently-cased or space-padded value is a different digest entirely.

Return value

string — 32 lowercase hexadecimal characters with no separators, measured with Length() on the page rather than assumed.

There is no closed set of sentinel values to test for: every input that is accepted produces a digest, and every input that is rejected aborts the page instead of returning an error token.

Behaviour

The digest is the real MD5 of the input, not a look-alike. Every value on this page was compared character for character against the same digest computed independently outside Marketing Cloud, over the same bytes. MD5("Hash probe 2026") gave 2bfdbd320b3b56c0d8c4be16462a96b7, and the official reference’s own example value reproduced exactly.

The bytes hashed are the UTF-8 encoding of the input. That cannot be seen with an ASCII string, because ASCII text has only one plausible encoding. Hashing a string containing ß, and ä gave 45e83c6ea8202aae452acf5f61f0d660, which is the digest of its UTF-8 bytes and not of the UTF-16 form the engine uses internally.

The second argument genuinely changes the value. The same input under UTF-16 gave 75300cf3b34da08a0cfd6958b26e1bae — a completely different digest, and the one you get from UTF-16 little-endian bytes. Encoding names are matched without regard to case: utf-8 and utf-16 behaved identically to their upper-case spellings.

The empty string is hashed, not refused. MD5("") returned d41d8cd98f00b204e9800998ecf8427e, the well-known digest of zero bytes.

A number is accepted and hashed as its decimal text. MD5(2026) gave c92a10324374fac681719d63979d00fe, which is the digest of the four characters 2026.

The encoding argument is stricter than it looks

ASCII is accepted, and it silently replaces every character it cannot represent with a question mark before hashing. The non-ASCII string above came back as 1a7a47e1752ce663f442793ac4b38476 — the digest of Grus? ??. Nothing warns you; the value is simply wrong for the input you passed.

An unrecognised name is not tolerated at all. banana, the dashless spelling UTF8, an empty string, and a number in that position each aborted the page with HTTP 422 rather than falling back to the default.

Show test script
%%[
  VAR @b, @a, @nb
  SET @b = RequestParameter("b")
  SET @a = "Hash probe 2026"
  SET @nb = Concat("Grus", Char(223), " ", Char(8364), Char(228))

  /* known-good control: renders on every request, so a run of HTTP 422s
     can be told apart from a broken deploy */
  OutputLine(Concat("CTRL=[", MD5(@a), "]"))

  /* the plain one-argument form, its length, and the empty-input digest */
  IF @b == "safe" THEN
    OutputLine(Concat("--- safe start ---"))
    OutputLine(Concat("M1=[", MD5(@a), "]"))
    OutputLine(Concat("ML=[", Length(MD5(@a)), "]"))
    OutputLine(Concat("EM=[", MD5(""), "]"))
    OutputLine(Concat("--- safe done ---"))
  ENDIF

  /* the second argument really changes the digest, and names are
     matched without regard to case */
  IF @b == "enc" THEN
    OutputLine(Concat("--- enc start ---"))
    OutputLine(Concat("M8=[", MD5(@a, "UTF-8"), "]"))
    OutputLine(Concat("M16=[", MD5(@a, "UTF-16"), "]"))
    OutputLine(Concat("CSLOW8=[", MD5(@nb, "utf-8"), "]"))
    OutputLine(Concat("CSLOW16=[", MD5(@nb, "utf-16"), "]"))
    OutputLine(Concat("--- enc done ---"))
  ENDIF

  /* the default encoding is the UTF-8 byte sequence, not the engine's
     internal UTF-16 form - only a non-ASCII input can tell them apart */
  IF @b == "nonascii" THEN
    OutputLine(Concat("--- nonascii start ---"))
    OutputLine(Concat("NBIN=[", @nb, "]"))
    OutputLine(Concat("NM8=[", MD5(@nb), "]"))
    OutputLine(Concat("NM16=[", MD5(@nb, "UTF-16"), "]"))
    OutputLine(Concat("--- nonascii done ---"))
  ENDIF

  /* ASCII silently substitutes a question mark for anything it cannot
     represent, which changes the digest without any signal */
  IF @b == "csascii" THEN
    OutputLine(Concat("--- csascii start ---"))
    OutputLine(Concat("CSASCII=[", MD5(@nb, "ASCII"), "]"))
    OutputLine(Concat("--- csascii done ---"))
  ENDIF

  /* a number is hashed as the text it renders as */
  IF @b == "numin" THEN
    OutputLine(Concat("--- numin start ---"))
    OutputLine(Concat("NUMIN=[", MD5(2026), "]"))
    OutputLine(Concat("--- numin done ---"))
  ENDIF

  /* each of the four branches below aborts the page - fetch alone */
  IF @b == "csbad" THEN
    OutputLine(Concat("--- csbad start ---"))
    OutputLine(Concat("CSBAD=[", MD5(@a, "banana"), "]"))
  ENDIF

  IF @b == "csnodash" THEN
    OutputLine(Concat("--- csnodash start ---"))
    OutputLine(Concat("CSNODASH=[", MD5(@nb, "UTF8"), "]"))
  ENDIF

  IF @b == "csnum" THEN
    OutputLine(Concat("--- csnum start ---"))
    OutputLine(Concat("CSNUM=[", MD5(@a, 8), "]"))
  ENDIF

  IF @b == "csempty" THEN
    OutputLine(Concat("--- csempty start ---"))
    OutputLine(Concat("CSEMPTY=[", MD5(@a, ""), "]"))
  ENDIF

  IF @b == "a0" THEN
    OutputLine(Concat("--- a0 start ---"))
    OutputLine(Concat("A0=[", MD5(), "]"))
  ENDIF

  IF @b == "a3" THEN
    OutputLine(Concat("--- a3 start ---"))
    OutputLine(Concat("A3=[", MD5(@a, "UTF-8", "extra"), "]"))
  ENDIF
]%%

Availability

Platform Available
Marketing Cloud Engagement Yes
Marketing Cloud Next No

See also