Guide
Pre-send verification in Salesforce Marketing Cloud
The most expensive email incident isn’t a bug the QA missed. It’s the version swap: QA approved the file on Tuesday, someone hotfixed a link on Wednesday, and the Thursday send went out unreviewed. The fix is to make the send itself ask: “is this exact file still the approved one?” Here is that gate for Salesforce Marketing Cloud, using SendLint’s verification API.
What you need
- A SendLint campaign whose round has been approved (approval mints the certificate that records each email’s SHA-256)
- A SendLint API key (created under API Keys in the app)
- SFMC Automation Studio access, with a Script Activity ahead of your Send Email activity
The gate, conceptually
One request. You hash the exact HTML you’re about to send and ask SendLint whether that fingerprint is on a standing certificate:
Authorization: Bearer sl_live_…
verified: true · status: valid → proceed to send
verified: false · status: not_found → never approved, or edited after — stop
verified: false · status: superseded → a newer approval replaced this file — stop
verified: false · status: revoked → approval was withdrawn — stop
The hash is SHA-256 over the file’s exact UTF-8 bytes, hex-encoded. Any byte changed after approval, even inside an invisible attribute, produces a different hash and a “stop” verdict. Personalization strings like %%FirstName%% are fine as long as you hash the same template bytes SendLint analyzed, before merge-field substitution.
The recipe in Automation Studio
- 1. Keep the approved file authoritative. The HTML you paste into Content Builder should be byte-identical to the file QA approved in SendLint. Treat any edit inside SFMC as a new round: re-run it through SendLint and re-approve, which mints a fresh certificate.
- 2. Add a Script Activity before the send. In server-side JavaScript, compute the SHA-256 of the approved HTML (SFMC’s AMPscript exposes a SHA256 function you can call from SSJS via TreatAsContent, or precompute the hash at upload time and store it in a Data Extension alongside the asset), then call the gate with HTTP.Get and your API key in the Authorization header.
- 3. Branch on the verdict. Parse the JSON. If verified is true, let the automation continue. If false, stop the automation and alert the team with the returned status and message — they say exactly why in plain language.
The simplest robust variant skips in-SFMC hashing entirely: compute the hash once at hand-off (shasum -a 256 launch-en.html on any machine), store it with the asset, and let the Script Activity just make the API call with the stored hash. Fewer moving parts, same guarantee, because the certificate is the thing being checked, not the courier.
An honest status note
The SendLint side of this recipe — certificates, the public verify page, and the /api/v1/verify gate — is live, tested, and what this guide is really about. The SFMC steps use stock platform features (Script Activities, HTTP.Get, Data Extensions) that your SFMC team already knows, but every Marketing Cloud org is configured differently: treat the recipe as the integration pattern, and validate the automation in your own business unit before relying on it for a production send. The same gate works from any CI system in two lines, which is also the quickest way to try it.
Frequently asked questions
- How do you gate a Salesforce Marketing Cloud send on QA approval?
- Add a Script Activity ahead of the Send Email activity. It hashes the approved HTML (or reads a precomputed hash from a Data Extension), calls SendLint's verification API with that fingerprint, and stops the automation unless the response confirms the exact file is on a standing certificate.
- What happens if the email is edited after approval?
- Any changed byte produces a different SHA-256, so the verification API returns verified false and the automation stops. The fix is to re-run the edited file through QA and re-approve it, which mints a fresh certificate.
- Does personalization break hash verification?
- No, as long as you hash the same template bytes SendLint analyzed, before merge-field substitution. Personalization strings like %%FirstName%% are part of the template and hash consistently.