Coforge SFMC Crash Courseone section at a time Β· ← β†’ move Β· Space=pause Β· M=mark for review
Left β€” Goal h

C00 β€” Start Here & How to Win This Interview

🎯 Why Coforge cares: this is a Technical Lead, financial-services, run-the-platform role. They want someone who can build, troubleshoot, and lead β€” and who answers practically, not just in theory. This crash course is engineered for fast recall and hands-on confidence.


🧠 One-screen mental model β€” the whole interview

        COFORGE SFMC TECHNICAL LEAD
                    β”‚
    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
   BUILD          RUN              LEAD
 (develop)     (support)        (own it)
    β”‚               β”‚               β”‚
 Email Studio   INC tickets     design + trade-offs
 Journey Bldr   RCA + SLA       mentoring
 AMPscript      troubleshoot    stakeholder comms
 DE/SQL/Auto    MOD (CRM)       financial-svc compliance
 APIs           critical issues estimation / peak
    β”‚               β”‚               β”‚
    └──── say it as: THEORY + "…and in practice I'd…" β”€β”€β”€β”€β”˜

The one habit that wins this interview: every answer = a crisp definition β†’ then "…and in practice, here's exactly what I'd click/write." That second half is what was missing last time. This course drills it into every module.


πŸ—ΊοΈ The Coforge JD β†’ which module

JD line Module(s)
Email campaigns & journeys (Email Studio + Journey Builder) C05, C06
Dynamic content via AMPscript + personalization C04
Data Extensions, SQL, Automation Studio C02, C03
Campaign validation, testing, preview, deployment C07 (practical core)
Distributed marketing / advisor communications C08 (JD-critical)
Data accuracy & segmentation C02, C03
Handle INC tickets (SFMC + MOD/CRM), RCA, SLA, critical issues C10 (JD-critical)
SFMC APIs C09
Financial-services domain + Technical-Lead behaviours C12
Deliverability & compliance C11
Big-picture / draw-it-on-a-whiteboard C01
Cram everything C13 (Memory Vault)
Fix the "too theoretical" problem C14 (Practical Drills + Mock)

🎯 The "Theory + Practical" answer formula (your LTM fix)

For ANY question, answer in 3 beats:

1. WHAT it is      β†’ one-sentence definition.
2. HOW it works    β†’ the mechanism / why.
3. IN PRACTICE     β†’ "I'd go to <Studio> > <screen> > <button>, set X,
                      test with Preview & Test, and verify in Tracking."

Example β€” "How do you personalise an email?" - What: AMPscript resolves per-subscriber values at send time. - How: Lookup/LookupOrderedRows pull from a DE; IF/ELSE branches content. - In practice: "In Content Builder I drop an HTML block, paste the AMPscript, guard every value with EMPTY() + a fallback, then Preview & Test against a real subscriber row and send a proof to my seed list before scheduling."

➑️ Practise this shape out loud for every rapid-fire Q in the course.


🧩 Master mnemonics (the spine β€” full list in C13)

  • BUILD / RUN / LEAD β€” the three hats this role wears (above).
  • Send flow = CAESPST β€” Content β†’ Audience β†’ Exclusions β†’ Send-class β†’ Preview β†’ Send β†’ Track (C05).
  • DE types = "Some Sendable Sharks Find Small Snacks" β†’ Standard, Sendable, Shared, Filtered, Synchronized, Salesforce DE (C02).
  • RCA = REPAIR-VP (RIRFVP) β€” Reproduce, Isolate layer, Root-cause, Fix, Verify, Prevent (C10).
  • Isolate the layer = DCRDI β€” Data β†’ Content β†’ Render β†’ Deliverability β†’ Integration (C10).
  • Auth = SPF/DKIM/DMARC β€” "who's allowed, did it change, what to do if it fails" (C11).

βœ… 12 things you must be able to DO live (not just describe)

  • [ ] Create a sendable DE + set the send relationship (click-path) β€” C02
  • [ ] Write a dedup query (ROW_NUMBER() … rn=1) from memory β€” C03
  • [ ] Write a suppression anti-join (NOT EXISTS / LEFT JOIN … IS NULL) β€” C03
  • [ ] Build the LookupOrderedRows β†’ RowCount β†’ Row β†’ Field loop blind β€” C04
  • [ ] Preview & Test AMPscript against a real subscriber + debug a blank β€” C04/C07
  • [ ] Build & send a campaign end-to-end; set up an A/B test β€” C05/C07
  • [ ] Build a welcome / advisor-onboarding journey β€” C06
  • [ ] Explain & set up a Distributed Marketing advisor send β€” C08
  • [ ] Get an OAuth token + fire a journey event in Postman β€” C09
  • [ ] Triage a Sev-1 send failure under SLA using RCA β€” C10
  • [ ] Diagnose "delivered but in spam" β€” C11
  • [ ] Tell a STAR story reframed for financial-services / lead lens β€” C12

πŸ•’ Suggested run order (~3 hours, paced by the timer)

First pass (memorise): C01 β†’ C02 β†’ C04 β†’ C03 β†’ C05 β†’ C06 β†’ C10 β†’ C08. Second pass (depth): C07, C09, C11, C12. Final hour: C13 Memory Vault (all diagrams + mnemonics) β†’ C14 mock out loud.

Tip: hit M to mark anything shaky; it collects in Marked for Review at the end.


πŸ› οΈ How to use this reader

  • Dark by default (πŸŒ“ toggles light). One subsection at a time.
  • ← / β†’ or Prev/Next to move. / to search the whole course.
  • ⏱ Timer auto-paces each section (default 3h goal β€” change it in the bar). Space pauses for breaks.
  • β˜† Mark / M flags a section β†’ see them all in Marked for Review.
  • πŸ–¨ PDF exports everything if you want it on your phone.

➑️ Next: C01_Big_Picture_Mental_Maps.md

C01 β€” The Big Picture (mental maps you can draw blind)

🎯 Why Coforge cares: as the SFMC Technical Lead you'll own campaigns, journeys, Data Extensions, automations and INC/RCA across multiple advisor BUs in a financial-services org β€” you must be able to whiteboard the whole platform and the data model on demand.

🧠 One-screen mental model

                 β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ SFMC (Engagement) ────────────────────────┐
                 β”‚                                                                    β”‚
   STUDIOS = channels (do work)            BUILDERS = setup (define data/logic/UI)    β”‚
   β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”          β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”   β”‚
   β”‚ Email Studio   (email)     β”‚          β”‚ Contact Builder (Contacts, attrs, DEs)β”‚   β”‚
   β”‚ Mobile Studio  (SMS/push)  β”‚          β”‚ Journey Builder (orchestration)       β”‚   β”‚
   β”‚ Web/Social/Adv Studio      β”‚          β”‚ Content Builder (emails/blocks/images)β”‚   β”‚
   β”‚ Automation Studio (batch)  β”‚          β”‚ Analytics Builder (reports)           β”‚   β”‚
   β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜          β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜   β”‚
                 β”‚                                                                    β”‚
   ACCOUNT TREE  β”‚                                                                    β”‚
   Enterprise (top, shared) ─▢ Parent BU ─▢ Child BU (Advisors-East) ─▢ Child BU(...) β”‚
                 β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

   THE PERSON:   Contact (1 per human, Contact Key) ──owns──▢ Subscriber (email channel, Subscriber Key)
                 Contact Key  ==  Subscriber Key   (same string; keep it stable!)

   THE FLOW:     Data Extension ──(audience)──▢ Email (AMPscript pulls fields) ──Send──▢
                 SAP/MTA delivers ──▢ Tracking (Opens/Clicks/Bounces) ──▢ Data Views / reports
STUDIOS = channels (DO work) BUILDERS = setup (DEFINE) Email Studio β€” send & manage email Mobile / Web / Advertising Studio Automation Studio β€” scheduled batch Contact Builder β€” Contacts & DEs Journey Builder β€” orchestration Content / Analytics Builder Builders define the pieces β†’ Studios use them to act
Enterprise (top / shared) Parent BU Child BU: Advisors-East Child BU: Advisors-West Child BU: Compliance
Data Extension Email (AMPscript) Send / MTA Inbox Tracking / Data Views DE = who/what Β· AMPscript = personalize Β· Send = deliver Β· Tracking = what happened

πŸ”‘ Core in 60 seconds

  • Studios DO, Builders DEFINE. Studios = channels that act (Email/Mobile/Web/Automation). Builders = where you set up data, journeys, content, reports (Contact/Journey/Content/Analytics).
  • Automation Studio is the odd one β€” named "Studio" but it's your batch engine (scheduled SQL, imports, file drops). Treat it as the back-office workhorse.
  • Account tree: Enterprise (top, can share data) β†’ Parent BU β†’ Child BUs. Each BU = a walled garden for users, data, sends. In FinServ you'll often have a BU per advisor segment / region / compliance.
  • One human = one Contact (identified by Contact Key). When you email them, the email channel sees them as a Subscriber (identified by Subscriber Key). These two keys are the SAME string.
  • All Contacts (Contact Builder, whole account) βŠ‡ All Subscribers (Email Studio). Every subscriber is a contact; not every contact is a subscriber.
  • Email flow = DE β†’ personalize β†’ send β†’ track. The DE is the audience + data; AMPscript pulls fields at send time; tracking lands in Data Views (_Sent, _Open, _Click, _Bounce, _Subscribers).
  • Subscriber Key is sacred: stable, unique, never reuse, never put the email address in it for FinServ (PII + key churn). Use a CRM/MOD contact id.

🧩 Mnemonics & memory hooks

  • Studios vs Builders β†’ "Build it, then Studio-use it." You Build the parts (Contact/Journey/Content/Analytics Builder), then a Studio puts them to work on a channel. Builders are nouns, Studios are verbs.
  • The 4 Builders β†’ "C-J-C-A: Cab Just Came Around." Contact, Journey, Content, Analytics.
  • The Studios β†’ "Every Morning Web Admins Automate" β†’ E-M-W-A: Email, Mobile, Web, Automation. (Hook: an admin every morning automates the channels.)
  • Account tree β†’ "EPC: Every Parent's Children." Enterprise β†’ Parent BU β†’ Child BUs.
  • Contact vs Subscriber β†’ "Same key, two hats." One person, one Contact Key; put on the "email hat" and that same key is the Subscriber Key.
  • Email flow β†’ "D-P-S-T: Don't Push Send Twice." Data Extension β†’ Personalize (AMPscript) β†’ Send β†’ Track.
  • Data Views β†’ "SOCBS" β†’ Sent, Open, Click, Bounce, Subscribers. Hook: "Send Often, Check Bounces, Suppress."

πŸ’€ Skeletons to memorize

The signature move of the whole platform: pull a row from a DE and personalize. Memorize this β€” it proves you know how a DE feeds an email.

%%[
  VAR @firstName, @advisor
  SET @firstName = [FirstName]                                    /* from sendable DE column */
  SET @advisor   = Lookup("Advisor_Lookup","AdvisorName","ContactKey", _subscriberkey)
]%%
Hi %%=v(@firstName)=%%, your advisor is %%=v(@advisor)=%%.

πŸ” Line by line: - VAR @firstName, @advisor β€” declare the variables before using them. - SET @firstName = [FirstName] β€” [FieldName] reads a column from the sendable DE (the audience row for this subscriber). - Lookup("Advisor_Lookup","AdvisorName","ContactKey", _subscriberkey) β€” fetch one value from another DE (Advisor_Lookup), returning AdvisorName where ContactKey = the built-in _subscriberkey. This is the cross-DE join you'll use constantly in FinServ. - %%=v(@advisor)=%% β€” v() outputs a variable's value into the rendered email.

The mental "schema" of any sendable Data Extension:

SubscriberKey | EmailAddress | FirstName | AdvisorName | ... 
(unique key)    (Email Addr   (any custom personalization fields)
                 field role)

πŸ” Line by line: - SubscriberKey β€” the column flagged as Subscriber Key (relationship field); must match Contact Key. - EmailAddress β€” the column flagged with the Email Address field role; tells the engine where to send. - Remaining columns β€” free-form personalization data (names, advisor, balances) read via [Column] in AMPscript.

πŸ› οΈ In practice (what you would actually click / do)

Find where you are (BU switch): top-right of SFMC β†’ click the BU dropdown (shows current Business Unit) β†’ pick the advisor/region BU. Everything you do is scoped to that BU.

Draw the data model live (Contact Builder): - App Switcher (top-left waffle / "Audience Builder" menu) β†’ Contact Builder. - Tabs you'll point to: Data Designer (links DEs to the Contact via attribute groups), Data Extensions (the tables), All Contacts (the master person list).

Make a sendable DE (the audience): - Email Studio β†’ Subscribers β†’ Data Extensions β†’ Create β†’ choose Standard β†’ name it β†’ on the Send Relationship step set it Sendable and map the Subscriber Key field to Subscriber Key and the email column to Email Address. - Add fields (FirstName, AdvisorName...) β†’ Save. Import rows via Import (file) or populate via an Automation Studio SQL Query activity.

Build & personalize the email (Content Builder): - Content Builder β†’ Create β†’ Email β†’ drag content blocks β†’ in a block click </> (HTML/AMPscript) β†’ drop the AMPscript skeleton above β†’ use Preview & Test with a real DE row to confirm %%=v()=%% resolves.

Send & validate: - In the email β†’ Send (Guided Send) β†’ choose the sendable DE as audience β†’ apply Suppression / Exclusion lists (critical in FinServ: opt-outs, do-not-contact, restricted advisors) β†’ schedule or send. - After send: Email Studio β†’ Tracking for opens/clicks/bounces; or query Data Views (_Sent, _Open, _Bounce) via an Automation SQL activity for RCA.

One-liner you can say: "I switch to the right BU, build a sendable DE in Email Studio, link it in Contact Builder, personalize in Content Builder with AMPscript, send via Guided Send with suppression applied, then validate in Tracking and Data Views."

🎀 Rapid-fire

  • Q: Studio vs Builder? A: Studios act on channels (Email/Mobile/Web/Automation); Builders define data/journeys/content/reports (Contact/Journey/Content/Analytics).
  • Q: Is Automation Studio a channel? A: No β€” it's the scheduled batch engine (SQL, imports, file transfers, send-triggering). …and in practice: I schedule a nightly Automation: File Drop β†’ Import β†’ SQL Query β†’ Send.
  • Q: Contact Key vs Subscriber Key? A: Same unique string for one person; "Contact Key" in Contact Builder/other channels, "Subscriber Key" in Email Studio.
  • Q: All Contacts vs All Subscribers? A: All Contacts = every person in the account; All Subscribers = the email-channel subset. Subscribers βŠ† Contacts.
  • Q: What is a sendable DE? A: A DE marked sendable with a Subscriber Key relationship + an Email Address field, so it can be used as a send audience. …and in practice: I set it on the Data Extension's Send Relationship step.
  • Q: Where does tracking live? A: In Tracking (UI) and Data Views (_Open, _Click, _Bounce, _Sent, _Subscribers) queryable by SQL. …and in practice: I write a SQL Query activity joining _Sent and _Bounce for an RCA report.
  • Q: Enterprise vs BU? A: Enterprise is the top account that can share content/data; BUs are isolated workspaces under it.
  • Q: Why not use email as Subscriber Key? A: Emails change β†’ key churn, duplicate contacts, broken history; and it spreads PII. Use a stable CRM/MOD id. …and in practice: I map the MOD ContactID into Subscriber Key on import.

⚠️ Gotchas / RCA hooks

  • Wrong BU = "missing" data. A DE/email/automation exists, but you're in the wrong Business Unit. RCA: check the BU dropdown first; data is BU-scoped (only shared/Enterprise data crosses).
  • Subscriber Key collisions / churn. Reusing or changing keys merges or splits people, corrupting tracking history. RCA: confirm the import maps a stable CRM/MOD id, not email; check for duplicate Contact Keys in All Contacts.
  • Non-sendable DE picked as audience. Send fails or field "Email Address" missing. RCA: open the DE β†’ Send Relationship β†’ ensure Sendable + Subscriber Key + Email Address field role set.
  • Personalization renders blank. %%=v(@x)=%% empty because the field isn't in the sendable DE or the Lookup missed. RCA: Preview & Test with a real row; verify column names and the lookup key (_subscriberkey) match exactly.
  • Suppression not applied β†’ compliance breach. In FinServ, sending to opt-outs/restricted advisors is a real incident. RCA: confirm Exclusion/Suppression list was attached in Guided Send; check All Subscribers status (Unsubscribed/Held) and publication-list opt-outs.
  • Counts don't reconcile (Sent vs Contacts). Bounces, held addresses, and suppressions reduce sent volume. RCA: join _Sent, _Bounce, _Subscribers in a SQL Query to explain the gap before raising it as a defect.

➑️ Next: C02_Data_Extensions_and_Model.md

C02 β€” Data Extensions & the Data Model

🎯 Why Coforge cares: every advisor journey, suppression list and SQL query you'll run for financial-services clients lives in a Data Extension β€” if you can't build, relate, and govern DEs by click, you can't manage segmentation, data accuracy, or RCA on data failures.

🧠 One-screen mental model

                         CONTACT BUILDER (the data brain)
        β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
        β”‚  ALL CONTACTS  ←──  ALL SUBSCRIBERS  (one row per ContactKey)  β”‚
        β”‚   (Contact mgmt)        status: Active / Held / Bounced /      β”‚
        β”‚                                 Unsubscribed                   β”‚
        β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                        β”‚ Send Relationship          β”‚ Data Designer
                        β”‚ (SubscriberKey β†’ All Subs)  β”‚ (DE ↔ DE links)
                        β–Ό                             β–Ό
   β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”     β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
   β”‚  SENDABLE DATA EXTENSION       β”‚     β”‚  ATTRIBUTE / LOOKUP DEs        β”‚
   β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚     β”‚  Accounts, Holdings, Prefs...  β”‚
   β”‚  β”‚ Field      β”‚ PK? Null? Len β”‚ β”‚     β”‚  joined on AdvisorID/ClientID  β”‚
   β”‚  β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ β”‚     β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
   β”‚  β”‚ ClientID   β”‚ PK  No   18   β”‚ β”‚
   β”‚  β”‚ EmailAddr  β”‚     No  254   β”‚ β”‚     LIST (legacy) ── tiny, by Email,
   β”‚  β”‚ FirstName  β”‚     Yes 100   β”‚ β”‚       no PK, profile attrs only.
   β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚       Use DEs for everything serious.
   β”‚  + Retention policy (delete)   β”‚
   β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

πŸ”‘ Core in 60 seconds

  • DE = a database table. Columns (fields) + rows (records). It is the unit of everything in modern SFMC: sends, journeys, SQL, imports.
  • List vs DE: List = old, keyed on Email, flat profile attributes, slow, no relationships. DE = relational, keyed on any field you choose, scales, supports SQL/Data Designer. In FS, always DEs.
  • A DE becomes Sendable when you (a) tick "Is Sendable" and (b) set a Send Relationship: "This DE field" β†’ relates to Subscribers on β†’ _SubscriberKey in All Subscribers.
  • Send Relationship purpose: tells SFMC who a row is (the Subscriber/Contact) so it can dedupe, honor unsubscribes, and write tracking back. Best practice = a stable ID (ClientID / ContactID), not email.
  • Primary Key (PK): makes a field unique β†’ enables overwrite/update on import instead of duplicate rows. No PK = append-only (duplicates pile up).
  • Nullable: field can be empty. Required (not null) rows fail import if blank.
  • Retention policy: auto-deletes data (whole DE, all records, or row-by-row by date). Critical for FS data minimization/compliance.
  • DE types (6): Standard, Filtered, Random, plus the flavors Sendable, Shared, Synchronized (+ Salesforce DEs created by sync). Filtered & Random are derived from a source DE.
  • Contact Builder = where contacts, attributes, and DE relationships (Data Designer) live. Data Designer = the canvas where you link DEs into one Contact data model.

🧩 Mnemonics & memory hooks

  • DE types β€” "Stan Filled Random Shared Sync'd Salesforce" β†’ Standard, Filtered, Random, Shared, Synchronized, Salesforce DE. Hook: "Stan filled random shared sync'd Salesforce drawers." Six drawers in the data cabinet.
  • Standard = you build the columns. Filtered = a saved WHERE clause over a source DE. Random = % sample for A/B. Shared = one DE visible across Business Units (Enterprise). Synchronized = a read-only mirror of a CRM object (via MC Connect). Salesforce DE = the sendable copy you build from a synchronized DE.

  • Sendable in 2 ticks β€” "TICK + LINK": TICK "Is Sendable", then LINK the field to All Subscribers _SubscriberKey. Hook: "Tick the box, link the soul."

  • Field config β€” "P.N.R.D." (sounds like "pin-ride"): Primary key? Nullable? Required? Default/Data-type/length. Hook: "PNRD every column before you save."

  • All Subscribers statuses β€” "A-HUB": Active, Held, Unsubscribed, Bounced. Hook: "Every contact parks in the A-HUB."

πŸ’€ Skeletons to memorize

A DE is built in the UI, but you must know its shape + how AMPscript writes to it and how SQL keys it.

1. The mental "CREATE TABLE" of a sendable DE (what the UI is really doing):

-- Conceptual shape of a sendable DE: Advisor_Clients
ClientID    VARCHAR(18)  PRIMARY KEY  NOT NULL   -- send relationship field
EmailAddress VARCHAR(254)             NOT NULL   -- the email column
FirstName   VARCHAR(100)              NULL
AdvisorID   VARCHAR(18)               NOT NULL   -- used to join in Data Designer
OptInStatus VARCHAR(20)               NULL
-- Send Relationship: ClientID  ->  Subscribers (_SubscriberKey) on All Subscribers
-- Retention: delete individual records 730 days after [LastModified]

πŸ” Line by line: - ClientID ... PRIMARY KEY NOT NULL β€” the unique, stable key; PK lets imports update a client instead of duplicating, and it's the field we make the send relationship. - EmailAddress VARCHAR(254) NOT NULL β€” every sendable DE must have an email-type field populated, else the row can't be mailed. - FirstName ... NULL β€” personalization field, allowed to be blank (nullable) so imports don't reject partial rows. - AdvisorID NOT NULL β€” the foreign-key-style field you'll link in Data Designer to the Advisor/Holdings DEs. - OptInStatus β€” FS marketing-preference flag you can filter on for compliant sends. - Send Relationship comment β€” points ClientID at _SubscriberKey in All Subscribers so tracking + unsubscribes reconcile. - Retention comment β€” auto-purges rows 730 days after last change = data minimization for compliance.

2. AMPscript: write a row into a DE (e.g. log a suppression / preference):

%%[
  UpsertData("Suppression_Master", 1,
    "ClientID", @clientId,
    "SuppressedReason", "CustomerRequest",
    "SuppressedDate", Now())
]%%

πŸ” Line by line: - UpsertData("Suppression_Master", 1, ...) β€” insert-or-update the DE named Suppression_Master; the 1 = number of key columns that follow. - "ClientID", @clientId β€” the key field + its value; because it's first and key-count is 1, an existing ClientID is updated, a new one is inserted (needs PK on ClientID). - "SuppressedReason", "CustomerRequest" β€” a non-key column written every time. - "SuppressedDate", Now() β€” stamps the suppression time; lets a retention/RCA query show when a client was suppressed.

3. SQL: build a sendable audience that EXCLUDES suppressions (the FS pattern):

SELECT  c.ClientID, c.EmailAddress, c.FirstName, c.AdvisorID
FROM    Advisor_Clients      c
LEFT JOIN Suppression_Master s  ON s.ClientID = c.ClientID
WHERE   s.ClientID IS NULL          -- not in suppression list
  AND   c.OptInStatus = 'Subscribed'

πŸ” Line by line: - SELECT c.ClientID... β€” pull only the fields the send/journey needs (ClientID is the send-relationship key). - FROM Advisor_Clients c β€” the master sendable DE. - LEFT JOIN Suppression_Master s ON s.ClientID = c.ClientID β€” attach any suppression row for that client. - WHERE s.ClientID IS NULL β€” keep only clients with no suppression match (anti-join = exclusion). - AND c.OptInStatus = 'Subscribed' β€” extra compliance gate so only opted-in advisors/clients are mailed.

πŸ› οΈ In practice (what you would actually click / do)

A) Create a Data Extension (Email Studio path β€” most common): 1. Email Studio β†’ Email β†’ Subscribers β†’ Data Extensions. 2. Pick a folder β†’ Create (top right). 3. Choose Standard (or Filtered / Random / From Template) β†’ OK. 4. Properties step: Name (Advisor_Clients), External Key (auto), folder; tick "Is Sendable" here if you know it's a send audience. Optionally tick "Is Testable". 5. Data Retention Policy step (toggle On): - Choose scope: Delete All Records, Delete Individual Records (by a date field), or Delete Records and Data Extension. - Set the period (e.g. Individual records, 730 days, based on LastModified). Save. 6. Fields step: add each field β†’ set Name, Data Type, Length, Nullable?, Primary Key?, Default. Mark ClientID as Primary Key + not nullable. Add an EmailAddress (Email type) field. 7. Send Relationship step (appears because Is Sendable): set "Send using" the EmailAddress field, and "Relates to Subscribers on" = ClientID β†’ _SubscriberKey (or Email if no key). Create.

Contact Builder path is equivalent: Contact Builder β†’ Data Extensions β†’ Create β€” same wizard. Use Contact Builder when the DE will be related in Data Designer.

B) Make an existing DE sendable / fix the relationship: - Open the DE β†’ Edit / Properties β†’ tick Is Sendable β†’ go to Send Relationship β†’ choose the send field + the All-Subscribers key field β†’ Save. (If greyed out: the DE has no email-type field β€” add one first.)

C) Relate DEs in Data Designer (Contact Builder): 1. Contact Builder β†’ Data Designer. 2. Find your starting point (a populated attribute group / the Advisor_Clients DE) β†’ Create Relationship / drag a link. 3. Set cardinality (One-to-One, One-to-Many) and the join fields (e.g. Advisor_Clients.AdvisorID β†’ Advisor_Master.AdvisorID). 4. Save. Now Contact Builder treats them as one model and you can build attribute-based journeys/segments across them.

D) Validate the data (so you don't repeat the "theory-only" miss): - DE β†’ Records tab to spot-check rows; Import to load a file (map columns, choose Overwrite / Add & Update β€” Add&Update needs the PK). - Query Studio / SQL Activity to count rows: SELECT COUNT(*) FROM Advisor_Clients. - Before a send: Send Preview / Preview & Test in Content Builder to confirm AMPscript pulls the right DE fields per ClientID.

🎀 Rapid-fire

  1. Q: List vs DE β€” when a List? A: Almost never now; only tiny legacy email-keyed lists. DEs for anything relational/scaled/compliant.
  2. Q: What makes a DE sendable? A: "Is Sendable" ticked and a Send Relationship to All Subscribers via a key field. …and in practice: Edit DE β†’ Properties β†’ tick β†’ Send Relationship tab β†’ map ClientID β†’ _SubscriberKey β†’ Save.
  3. Q: Why use ClientID not Email as the send relationship? A: Stable across email changes, dedupes per person, cleaner cross-BU reconciliation; FS clients change emails but not their ID.
  4. Q: Primary Key effect? A: Enforces uniqueness β†’ enables update-on-import; without it, re-imports create duplicate rows.
  5. Q: Filtered vs Random DE? A: Filtered = saved WHERE-clause subset of a source DE; Random = % sample for A/B testing.
  6. Q: Synchronized vs Salesforce DE? A: Synchronized = read-only mirror of a CRM object via MC Connect; you build a sendable Salesforce DE from it to actually mail. …and in practice: Contact Builder β†’ Salesforce Data Extensions β†’ select object β†’ create the sendable copy.
  7. Q: All Subscribers statuses? A: Active, Held, Unsubscribed, Bounced (A-HUB).
  8. Q: How do you suppress clients globally? A: Maintain a Suppression_Master DE, LEFT JOIN-exclude it in the send SQL, or add it as an Exclusion/Suppression list on the send definition. …and in practice: in the Guided Send, the Suppression Lists step lets you attach a DE to remove those rows.
  9. Q: Retention policy options? A: Delete all records / delete individual records by date / delete records + the DE itself; on a period you set.

⚠️ Gotchas / RCA hooks

  • "Send Relationship" greyed out / DE not sendable β†’ no Email-type field exists. RCA: add an Email data-type field, re-open Send Relationship.
  • Duplicate rows after every import β†’ DE has no Primary Key. RCA: check field config; recreate DE with PK (you can't add a PK to a populated DE β€” you re-create + reload).
  • Import rows rejected β†’ a Required (non-nullable) field was blank, or value exceeds Length, or PK collision. RCA: open Import Activity logs / error file, check the failing column.
  • Data silently disappears β†’ a Retention Policy is purging it. RCA: DE β†’ Properties β†’ Data Retention; confirm period + the date field it keys on. Common surprise in FS where someone set aggressive minimization.
  • Send to suppressed/opted-out client (compliance incident) β†’ suppression DE not joined or not attached as a suppression list, or join key mismatch (Email vs ClientID). RCA: verify the exclusion JOIN keys match and the suppression DE is on the send definition; re-run the audience query and diff counts.
  • Synced DE looks stale β†’ MC Connect sync paused or object not in the sync; RCA: Contact Builder β†’ Data Sources β†’ Synchronized Data Sources β†’ check status/last run.
  • Cross-BU data missing β†’ DE is local, not Shared. RCA: recreate in the Shared folder / Shared Data Extensions so child BUs see it.

➑️ Next: C03_SQL_and_Automation_Studio.md

C03 β€” SQL & Automation Studio

🎯 Why Coforge cares: this is the engine room of the JD β€” segmentation, data accuracy, scheduled advisor sends, and the RCA muscle to explain why a query emptied a DE or blew the SLA on a financial-services campaign.

🧠 One-screen mental model

   SOURCE DEs / DATA VIEWS                 SQL QUERY ACTIVITY                 TARGET DE
   β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”                  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”             β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
   β”‚ Advisors_Master   β”‚  SELECT ...      β”‚  runs SQL on the β”‚  writes β†’   β”‚ Send_Audienceβ”‚
   β”‚ _Sent / _Open ... β”‚ ───────────────▢ β”‚  source, picks   β”‚ ──────────▢ β”‚ (must exist  β”‚
   β”‚ Transactions_DE   β”‚  FROM / JOIN     β”‚  Overwrite/      β”‚             β”‚  already!)   β”‚
   β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  WHERE           β”‚  Update/Append   β”‚             β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                                          β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜                    β”‚
   SFMC SQL = SELECT-ONLY. No UPDATE/DELETE/INSERT statements.                    β”‚ feeds
   You never "write SQL into" a DE β€” you SELECT and the activity LANDS the rows.   β–Ό
                                                                            Journey / Send

   AUTOMATION STUDIO = the conveyor belt that runs activities in ORDER:
   β”Œβ”€β”€β”€β”€β”€β”€β”   β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”   β”Œβ”€β”€β”€β”€β”€β”€β”€β”   β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”   β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”   β”Œβ”€β”€β”€β”€β”€β”€β”
   β”‚Import│──▢│ Query  │──▢│Filter │──▢│Verify(DE)│──▢│ Send Email   │──▢│Extractβ”‚
   β””β”€β”€β”€β”€β”€β”€β”˜   β””β”€β”€β”€β”€β”€β”€β”€β”€β”˜   β””β”€β”€β”€β”€β”€β”€β”€β”˜   β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜   β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜   β””β”€β”€β”€β”€β”€β”€β”˜
   Trigger: ⏰ Scheduled (calendar)   OR   πŸ“‚ File-Drop (file lands on SFTP)

πŸ”‘ Core in 60 seconds

  • SFMC SQL is a T-SQL subset, SELECT-only. No UPDATE/DELETE/INSERT/MERGE/stored procs/temp tables/CTEs-with-writes. You SELECT; the activity writes the result.
  • The write happens via the Query Activity's Target DE + Update Type β€” not in the SQL.
  • 3 update types β€” pick deliberately:
  • Overwrite = truncate target, then load. (Zero rows returned β‡’ target ends EMPTY.)
  • Update = match on the target DE's Primary Key, update matches + insert new (upsert-ish).
  • Append = add rows, no delete (can create duplicates / PK errors).
  • Target DE must already exist with matching column names; the query maps result columns β†’ target columns by name.
  • Data Views = system tables of send/engagement history: _Sent, _Open, _Click, _Bounce, _Unsubscribe, _Subscribers, _Job. Underscore prefix, ~6 months retention.
  • Join engagement data on SubscriberKey + JobID (JobID = one send). SubscriberKey alone mixes sends together.
  • Automation Studio runs activities sequentially; failure of one step (by default) stops the chain.
  • Two trigger types: Scheduled (run at a time/recurrence) or File-Drop (run when a file lands on the Enhanced FTP / Import directory).
  • Verification activity = a safety gate: stop/email if target DE row count is too low/high/zero β€” your anti-disaster guard for advisor sends.

🧩 Mnemonics & memory hooks

  • Update types β€” "OUA = Obliterate, Upsert, Add":
  • Obliterate β†’ Overwrite (wipes first β€” dangerous on empty results)
  • Upsert β†’ Update (matches PK)
  • Add β†’ Append (piles on, dup risk)
  • Automation activities β€” "I Query For Sweet Verified Emails, Wait, eXtract & Transfer" β†’ I-Q-F-S-V-E-W-X-T:
  • Import Β· Query (SQL) Β· Filter Β· Script (SSJS) Β· Verification Β· Email (Send) Β· Wait Β· eXtract (Data Extract) Β· Transfer (File Transfer)
  • Sticky line: "I query for sweet, verified emails, wait, then extract & transfer."
  • Data Views β€” "SOCUB-J": Sent Β· Open Β· Click Β· Unsub Β· Bounce Β· Job. (Hook: "so-cub-j" = the cub cubs that track every send.)
  • Join key β€” "Same person, same SEND": SubscriberKey + JobID. (Hook: who + which send.)
  • Trigger types β€” "Clock or Drop": ⏰ Scheduled vs πŸ“‚ File-Drop.

πŸ’€ Skeletons to memorize

1) Dedup β€” keep newest row per advisor (ROW_NUMBER)

SELECT SubscriberKey, EmailAddress, AdvisorID, ModifiedDate
FROM (
    SELECT
        SubscriberKey, EmailAddress, AdvisorID, ModifiedDate,
        ROW_NUMBER() OVER (
            PARTITION BY SubscriberKey
            ORDER BY ModifiedDate DESC
        ) AS rn
    FROM Advisors_Master
) ranked
WHERE rn = 1

πŸ” Line by line: - SELECT ... FROM ( ... ) ranked β€” outer query reads from an inner derived table aliased ranked. - ROW_NUMBER() OVER (...) β€” numbers rows 1,2,3… within each group. - PARTITION BY SubscriberKey β€” restart the numbering for every distinct subscriber. - ORDER BY ModifiedDate DESC β€” newest record gets number 1. - AS rn β€” name that number column. - WHERE rn = 1 β€” keep only the single freshest row per subscriber β†’ deduped.

2) Anti-join suppression β€” eligible advisors NOT bounced/unsubbed

SELECT a.SubscriberKey, a.EmailAddress, a.AdvisorID
FROM Advisors_Master a
LEFT JOIN Suppression_DE s
    ON a.SubscriberKey = s.SubscriberKey
WHERE s.SubscriberKey IS NULL

πŸ” Line by line: - FROM Advisors_Master a β€” main audience, aliased a. - LEFT JOIN Suppression_DE s β€” keep ALL advisors, attach suppression match if any. - ON a.SubscriberKey = s.SubscriberKey β€” match the two on the key. - WHERE s.SubscriberKey IS NULL β€” keep only rows with no match in suppression β†’ the safe, sendable list. (This is the classic "anti-join".)

3) Engagement join β€” who OPENED a specific send (SubscriberKey + JobID)

SELECT s.SubscriberKey, s.EmailAddress, o.EventDate
FROM _Sent s
INNER JOIN _Open o
    ON s.SubscriberKey = o.SubscriberKey
   AND s.JobID        = o.JobID
WHERE s.JobID = 12345

πŸ” Line by line: - FROM _Sent s β€” start from the send log (one row per send-to-subscriber). - INNER JOIN _Open o β€” keep only subscribers who have a matching open. - ON ... SubscriberKey AND ... JobID β€” match on both so you don't blend other campaigns. - WHERE s.JobID = 12345 β€” scope to one specific send (Job). Swap _Open for _Click/_Bounce for other metrics; LEFT JOIN ... WHERE o.SubscriberKey IS NULL = sent but did NOT open.

πŸ› οΈ In practice (what you would actually click / do)

A. Build a Query Activity 1. Automation Studio β†’ Activities β†’ Query β†’ Create Activity (or build it inside an Automation's canvas via Add Activity β†’ SQL Query β†’ Create New). 2. Name + External Key (use a naming convention, e.g. QRY_Advisor_Eligible_Daily). 3. Write SQL in the editor β†’ click Validate Syntax (catches T-SQL errors before runtime). 4. Target Data Extension: pick the existing DE (or Create New DE from the wizard β€” define columns + Primary Key here; PK drives Update behavior). 5. Data Action (Update Type): choose Overwrite / Update / Append (see OUA mnemonic). 6. Save. Run once standalone (Start) to test; check the target DE β†’ Records tab for row count.

B. Chain it into an Automation 1. Automation Studio β†’ Overview β†’ New Automation. 2. Drag a Schedule (⏰) or File Drop (πŸ“‚) trigger into the Starting Source slot. - File Drop: set the Filename pattern + the FTP folder to watch (e.g. /Import/advisors_*.csv). 3. On the canvas, drag activities into Steps in order, e.g. Step 1 Import File β†’ Step 2 SQL Query β†’ Step 3 Verification β†’ Step 4 Send Email β†’ Step 5 Data Extract β†’ Step 6 File Transfer. (Activities in the same step run in parallel; separate steps run in sequence.) 4. Click each activity tile β†’ Choose an existing one or Create New inline.

C. Add a Verification step (the safety gate) 1. Add activity β†’ Verification. 2. Pick the target DE to check (your Send_Audience). 3. Set the rule, e.g. Record count is less than 1 β†’ Action: Stop the automation and notify, enter your alert email. 4. Place it after the Query, before the Send so a bad/empty audience never reaches advisors.

D. Schedule it 1. Open the automation β†’ Schedule button (top-right) β†’ set Start date/time, time zone, recurrence (e.g. Daily 06:00) and end condition. 2. Activate the schedule. For File-Drop, just Activate β€” it now fires on file arrival. 3. Monitor under Automation Studio β†’ Overview (status: Running/Complete/Error) and the Activity log.

E. Test/validate before deploy - Run the Query standalone first; eyeball the target DE record count and a few rows. - Use a test/staging target DE with Overwrite off (use Append) until counts look right. - Add a Verification gate, then a single full dry-run of the automation in a lower BU before activating the schedule.

🎀 Rapid-fire

  • Q: Can SFMC SQL do an UPDATE statement? β†’ A: No β€” SELECT only. You "update" by selecting rows into a target DE with Update action. …and in practice: the row matching uses the target DE's Primary Key; no PK β‡’ Update behaves like insert/dup.
  • Q: Overwrite vs Update vs Append? β†’ A: Overwrite wipes-then-loads; Update upserts on PK; Append adds without deleting. …and in practice: I default daily audiences to Overwrite, but guard it with a Verification step so an empty result can't blank the DE.
  • Q: How do you join send to opens? β†’ A: _Sent β‹ˆ _Open on SubscriberKey AND JobID. …and in practice: JobID scopes it to one send; SubscriberKey alone double-counts across campaigns.
  • Q: How long do Data Views keep data? β†’ A: ~6 months (rolling). Persist longer by querying into your own DE on a schedule.
  • Q: Same-step vs separate-step activities? β†’ A: Same step = parallel; separate steps = sequential. …and in practice: I put Query and Send in different steps so the send never starts before the audience is built.
  • Q: Scheduled vs File-Drop? β†’ A: Scheduled runs on a clock; File-Drop runs when a file lands on Enhanced FTP. …and in practice: advisor lists from an upstream system β†’ File-Drop; nightly refresh β†’ Scheduled.
  • Q: How do you stop a bad audience reaching advisors? β†’ A: A Verification activity that stops + emails on row-count < 1 (or an unexpected spike), placed before Send.
  • Q: How do you get data OUT of SFMC? β†’ A: Data Extract (DE/data view β†’ file) then File Transfer to the SFTP. (Mnemonic tail: …eXtract & Transfer.)

⚠️ Gotchas / RCA hooks

  • Empty audience (0 rows sent). RCA: open the Query β†’ run standalone β†’ check returned count. Common causes: a WHERE filter on a date/flag, a JOIN that became an inner-join filter, or the source DE didn't import (Import step failed earlier). Fix: validate each step's row count top-to-bottom; add a Verification gate so it's caught next time.
  • Overwrite wiped a DE. RCA: the Query returned 0 rows (failed join, bad import, source empty) and Overwrite truncated first β†’ DE ends empty. Fix: switch critical loads to Update, or front it with Verification (count < 1 β‡’ stop); restore from a backup DE / re-run upstream import.
  • Query timeout (~30 min limit). RCA: huge cross-join, missing WHERE, dedup over a giant DE, non-sargable filters. Fix: filter early, dedup into a smaller staging DE first, index the matching/PK fields on DEs used in joins, split into multiple queries.
  • Duplicates in target. RCA: Append without a PK, or a one-to-many JOIN fanning out rows. Fix: use the ROW_NUMBER dedup skeleton; set a Primary Key + use Update.
  • Column not populating. RCA: result column name β‰  target DE column name (mapping is by name). Fix: alias in SQL (SELECT x AS TargetColName).
  • Automation stuck/errored. RCA: check Automation Studio β†’ Overview β†’ Error + the failing activity's run log; File-Drop didn't fire β‡’ wrong filename pattern/FTP folder. Fix: correct pattern, re-drop file, confirm Enhanced FTP path.
  • SLA breach on an INC. Triage order: Is data there? (source DE/import) β†’ Did the query return rows? β†’ Did the send/journey fire? β†’ Was anyone suppressed wrongly? Tie the finding to a single failing step for a crisp RCA.

➑️ Next: C04_AMPscript_and_Dynamic_Content.md

C04 β€” AMPscript & Dynamic Content

🎯 Why Coforge cares: the JD is built on "dynamic content via AMPscript + personalization" for advisor communications β€” you must show you can hand-build a personalized, compliant financial-services email, not just describe it.

🧠 One-screen mental model

   SENDABLE DE / Journey data           Reference DEs (lookups)
   FirstName, AdvisorId, Tier            Advisors, Accounts, Disclosures
        |                                        |
        v                                        v
   %%FirstName%%  /  AttributeValue("..")   Lookup() / LookupRows()
        |                                        |
        +------------------+---------------------+
                           v
                 %%[  AMPscript block  ]%%   <-- logic, VAR/SET/IF, loops
                           |
                           v
              %%=v(@var)=%%  /  ContentBlockByKey("..")   <-- OUTPUT
                           |
                           v
          RENDERED HTML  (per subscriber, at send/render time)
                           |
                  +--------+--------+
                  v                 v
             EMAIL SEND        CLOUDPAGE
          (sendable DE ctx)  (RequestParameter / no send ctx)
  • AMPscript runs server-side, once per subscriber, at render time. Recipient sees only HTML.

πŸ”‘ Core in 60 seconds

  • Three delimiters: %%[ logic ]%% (no output) Β· %%=v(@x)=%% (inline output) Β· %%FieldName%% (personalization string).
  • %%field%% vs AttributeValue("field") β€” same source (send context), but AttributeValue() is callable inside a block and accepts a dynamic name; %%field%% is a literal token only.
  • Lookup family returns from reference DEs (not the sendable DE): Lookup = one value Β· LookupRows/LookupOrderedRows = a rowset you loop.
  • 2,000-row cap: ordered lookups return all matching rows up to 2,000 when the count arg is <1. Always pass a sane numRows.
  • ContentBlockByKey pulls a Content Builder block by its Customer Key = modular/reusable content (legal footers, disclosures).
  • Dynamic Content block (drag-drop, rules in UI) vs AMPscript β€” UI for marketers/simple rules; AMPscript for data-driven, multi-DE, looped logic.
  • Send context vs CloudPage context β€” email send has a subscriber + sendable DE; a CloudPage does not, so you use RequestParameter() and explicit lookups.

🧩 Mnemonics & memory hooks

  • Lookup family β€” "1 ROW, ROWS, ORDER":
  • Lookup = 1 value (one field, first match).
  • LookupRows = ROWS (a set, unordered).
  • LookupOrderedRows = ROWS in ORDER (you give the sort).
  • Hook: "One, many, many-sorted."
  • The Rows loop β€” "C-R-F" = Count, Row, Field: RowCount β†’ Row(@rs, i) β†’ Field(@row, "Col"). Hook: "Count the Rows, then Fetch each Field."
  • Block anatomy β€” "V-S-I-O" = VAR, SET, IF, Output: declare, assign, branch, emit. Hook: "Very Smart If Output."
  • Output safely β€” v() then Empty(): wrap vars in v(), guard with Empty()/IIF(). Hook: "V for visible, E for empty-check."
  • 2,000 = the wall: ordered lookups stop at 2,000 rows by default β€” "two grand and you're grounded."

πŸ’€ Skeletons to memorize

1) Greeting + fallback (the #1 warm-up)

%%[
  VAR @first, @greeting
  SET @first = AttributeValue("FirstName")
  IF Empty(@first) THEN
    SET @greeting = "Hello"
  ELSE
    SET @greeting = Concat("Hello ", @first)
  ENDIF
]%%
<p>%%=v(@greeting)=%%, thank you for banking with us.</p>

πŸ” Line by line: - VAR @first, @greeting β€” declare two script variables (every var starts with @). - SET @first = AttributeValue("FirstName") β€” pull FirstName from the send context; returns "" (not an error) if the column is missing. - IF Empty(@first) THEN β€” true when null/blank; this is your fallback guard. - SET @greeting = "Hello" β€” safe default so no "Hello ," with a missing name. - ELSE ... Concat("Hello ", @first) β€” personalize when we have a name. - %%=v(@greeting)=%% β€” v() outputs a variable inline into the HTML.

2) Single Lookup (one value from a reference DE)

%%[
  VAR @advisorName
  SET @advisorName = Lookup("Advisors", "FullName", "AdvisorId", AttributeValue("AdvisorId"))
]%%
<p>Your advisor is %%=v(@advisorName)=%%.</p>

πŸ” Line by line: - Lookup("Advisors", "FullName", ...) β€” args = DE name, column to return, filter column, filter value. - AttributeValue("AdvisorId") β€” the subscriber's advisor id from send data is the filter value. - Returns the first match's single field; "" if no match β€” so guard it before display.

3) LookupOrderedRows β†’ RowCount β†’ Row β†’ Field loop

%%[
  VAR @rows, @count, @i, @row, @amt
  SET @rows  = LookupOrderedRows("Accounts", 5, "Balance DESC", "CustomerId", AttributeValue("CustomerId"))
  SET @count = RowCount(@rows)
  IF @count > 0 THEN
    FOR @i = 1 TO @count DO
      SET @row = Row(@rows, @i)
      SET @amt = Field(@row, "Balance")
]%%
      <tr><td>%%=v(Field(@row,"AccountName"))=%%</td><td>%%=v(@amt)=%%</td></tr>
%%[
    NEXT @i
  ENDIF
]%%

πŸ” Line by line: - LookupOrderedRows("Accounts", 5, "Balance DESC", ...) β€” args = DE, max rows (5, NOT 0/blank or you risk the 2,000 cap), ORDER BY string, filter col, filter val. - RowCount(@rows) β€” how many rows came back; always check > 0 before looping (no rows = skip, no error). - FOR @i = 1 TO @count DO β€” AMPscript loops are 1-based. - Row(@rows, @i) β€” grab the i-th row object. - Field(@row, "Balance") β€” read a named column from that row. - The <tr> lives outside the block (between ]%% and %%[) so HTML renders each iteration; logic resumes in the next %%[.

4) Conditional content IF / ELSEIF / ELSE (account tier)

%%[
  VAR @tier, @offer
  SET @tier = AttributeValue("AccountTier")
  IF @tier == "Platinum" THEN
    SET @offer = ContentBlockByKey("offer-platinum")
  ELSEIF @tier == "Gold" THEN
    SET @offer = ContentBlockByKey("offer-gold")
  ELSE
    SET @offer = ContentBlockByKey("offer-standard")
  ENDIF
]%%
%%=v(@offer)=%%

πŸ” Line by line: - SET @tier = AttributeValue("AccountTier") β€” read the segmentation field driving the branch. - IF ... ELSEIF ... ELSE ... ENDIF β€” exactly one branch wins; ENDIF is mandatory. - ContentBlockByKey("offer-platinum") β€” pulls a reusable Content Builder block by its Customer Key, so marketers edit the block, not the code. - %%=v(@offer)=%% β€” emit the chosen block's rendered HTML.

5) Write-back: UpsertData / UpsertDE (log the send)

%%[
  UpsertData("SendLog", 1, "SubscriberKey", _subscriberkey,
             "LastSent", Now(), "Campaign", "Q3-AdvisorUpdate")
]%%

πŸ” Line by line: - UpsertData("SendLog", 1, ...) β€” args = target DE, # of key columns (1), then key col/value pairs, then update col/value pairs. - "SubscriberKey", _subscriberkey β€” the 1 key column + its value (_subscriberkey is a built-in system var). - "LastSent", Now() / "Campaign", "..." β€” non-key columns to write; Upsert = update if key exists, else insert. - Use for per-subscriber audit/suppression logging β€” critical for financial-services compliance trails.

πŸ› οΈ In practice (what you would actually click / do)

Where AMPscript lives (the click-path): 1. Content Builder β†’ open the email β†’ drop an HTML block (or Code Resource for a CloudPage). AMPscript goes inside an HTML/Code block β€” there is no "AMPscript block" tile. 2. Type the %%[ ]%% logic at the top, output with %%=v()=%% / %%field%% in the body. 3. For reusable pieces, create the disclosure/footer as its own Content Builder block, copy its Customer Key (right-click block β†’ properties, or set it on save), and call ContentBlockByKey("that-key").

Preview & Test against a real subscriber (this is what tripped you up β€” say it out loud): 1. In the email editor click Preview and Test. 2. Set the "Preview using" data source to your sendable Data Extension (or paste a Subscriber Key) β€” this is how AMPscript gets real values; with no data source AttributeValue() returns blank. 3. Step through different subscribers (Platinum vs Standard, advisor present vs missing) to prove each branch. 4. Send Preview / Test Send to a seed/test address to confirm the rendered HTML, then validate with Salesforce Marketing Cloud's email-validation/ "Validate" before deployment.

Debug a BLANK personalization (the RCA you must narrate): 1. Open Preview and Test, pick a subscriber you know has the value β€” still blank? β†’ it's the data source / context, not the code. 2. Check the exact field name & casing in AttributeValue("FirstName") matches the DE column. 3. Confirm the field is in the sendable DE / Journey entry data β€” a reference-only field needs a Lookup, not %%field%%. 4. Add a temporary debug line %%=v(@first)=%% or output AttributeValue("...") raw to see what render time actually has. 5. For lookups: verify the DE name + filter value match (whitespace, leading zeros on AdvisorId) β€” wrong filter = empty rowset, not an error.

Dynamic Content block vs AMPscript β€” how you decide on the spot: simple "if Region = X show banner Y" with marketer-editable rules β†’ Dynamic Content block (Content Builder β†’ drag the Dynamic Content tile, define rules in the UI). Multi-DE lookups, loops, write-back, or compliance logic β†’ AMPscript in an HTML block.

🎀 Rapid-fire

  • Q: Difference between Lookup and LookupRows? A: Lookup returns one field value; LookupRows/LookupOrderedRows return a rowset you loop with RowCount/Row/Field. …and in practice: I use Lookup for "advisor name", LookupOrderedRows for "last 5 transactions, newest first."
  • Q: %%field%% vs AttributeValue("field")? A: Same send-context source; AttributeValue() works inside a block and takes a dynamic name, %%field%% is a literal token. …and in practice: inside %%[ ]%% I always use AttributeValue().
  • Q: What's the 2,000-row thing? A: Ordered lookups cap at 2,000 rows when the count arg is <1. …and in practice: I always pass an explicit numRows and let SQL/Automation do bulk work, not AMPscript.
  • Q: How do you make content reusable? A: Build it as a Content Builder block and call ContentBlockByKey("customerKey"). …and in practice: disclosures/footers live in one block so legal edits hit every email at once.
  • Q: What does TreatAsContent do? A: It re-processes stored AMPscript that you pulled from a DE/block as live AMPscript instead of plain text. …and in practice: if a footer stored in a DE contains AMPscript, I wrap the output in TreatAsContent() so it actually runs.
  • Q: AMPscript runs where/when? A: Server-side, per subscriber, at send/render time β€” never client-side.
  • Q: How do you test it? A: Preview and Test with the sendable DE as the data source, step subscribers, test-send a seed. …and in practice: I deliberately test the empty/fallback case, not just the happy path.
  • Q: Email vs CloudPage context? A: Email has subscriber + sendable DE; a CloudPage has no send context, so I read RequestParameter() and do explicit Lookups.

⚠️ Gotchas / RCA hooks

  • Blank personalization β†’ 90% data/context, not code. RCA: Preview with a known-good subscriber; if still blank, the field isn't in send data β†’ Lookup it.
  • Field name / casing / whitespace mismatch β†’ silent empty string. RCA: compare AttributeValue("...") literal to the DE column; check leading zeros on IDs (AdvisorId).
  • Forgetting the RowCount > 0 guard β†’ loop on an empty set or odd output. RCA: always branch on count before FOR.
  • numRows < 1 on ordered lookups β†’ silently capped at 2,000, partial data. RCA: pass an explicit count; for big sets use SQL.
  • Stored AMPscript renders as raw text β†’ you forgot TreatAsContent(). RCA: wrap DE-sourced content that contains AMPscript.
  • Wrong ContentBlockByKey key β†’ block doesn't render / errors. RCA: re-copy the Customer Key from the block's properties; keys are case/space-sensitive.
  • Compliance trap (financial services): never expose full account numbers / SSNs in %%field%%; mask in SQL/AMPscript and confirm suppression lists applied before send. RCA on a misfire: pull the SendLog write-back to prove who received what.
  • Unbalanced %%[ ]%% or missing ENDIF/NEXT β†’ render error or leaked code. RCA: validate fences and that every IF/FOR is closed before deploy.

➑️ Next: C05_Email_Studio_and_Content_Builder.md

C05 β€” Email Studio & Content Builder

🎯 Why Coforge cares: this is the JD's core engine β€” you "run email campaigns, do dynamic content + personalization, validate/preview/test/deploy, and pick the right send classification" for advisor & financial-services comms where a wrong From-line or missing suppression is a compliance incident.

🧠 One-screen mental model

                         β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
                         β”‚            EMAIL STUDIO               β”‚
                         β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
   CONTENT BUILDER                 THE SEND FLOW (left β†’ right)
   β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
   β”‚ Template      β”‚     1.CONTENT  2.AUDIENCE  3.EXCLUDE   4.CLASSIFY
   β”‚  β”” Slots      β”‚     β”Œβ”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
   β”‚     β”” Blocks  β”‚ ──► β”‚ Email │─►│  DE /   │─►│ Suppr. │─►│ Send Class. β”‚
   β”‚  (free-form / β”‚     β”‚ (HTML β”‚  β”‚ List /  β”‚  β”‚ + Excl β”‚  β”‚  Sender +   β”‚
   β”‚   AMPscript)  β”‚     β”‚ +AMP) β”‚  β”‚ Filter) β”‚  β”‚ lists  β”‚  β”‚  Delivery + β”‚
   β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜     β””β”€β”€β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β”‚ Comm/Trans  β”‚
                                                            β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”˜
                              7.TRACK   6.SEND/SCHED  5.PREVIEW/TEST  β”‚
                            β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”‚
                            β”‚ Opens  β”‚β—„β”‚ Send Now β”‚β—„β”‚ VAWP + Proofβ”‚β—„β”€β”˜
                            β”‚ Clicks β”‚ β”‚ /Scheduleβ”‚ β”‚ (test send) β”‚
                            β”‚ Bounce β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                            β””β”€β”€β”€β”€β”€β”€β”€β”€β”˜

   HOW IT'S TRIGGERED:
   User-Initiated (Guided Send)  β€’  Triggered Send (TSD, event)  β€’  Transactional API (REST, 1:1)

πŸ”‘ Core in 60 seconds

  • Send flow = CAESPST: Content β†’ Audience β†’ Exclusions β†’ Send-classification β†’ Preview/test β†’ Schedule/send β†’ Track.
  • Send Classification = Sender Profile + Delivery Profile + CAN-SPAM type.
  • Sender Profile = WHO it's from: From Name, From Email, Reply-to.
  • Delivery Profile = HOW it ships: IP/sending domain, header & footer (physical address + unsubscribe).
  • Type = Commercial (marketing β€” footer + unsub honored) vs Transactional (receipts/OTP/statements β€” bypasses unsub & some suppression).
  • 3 ways to send: User-Initiated (manual Guided Send), Triggered (TSD fires on an event), Transactional (REST API, real-time 1:1, no unsub footer).
  • Native A/B test: ONE variable, a % test split, winner by open or click rate, remainder auto-gets the winner. Tie β†’ Condition A wins.
  • Content Builder hierarchy: Template β†’ Slots β†’ Blocks. Blocks hold the content (text, image, HTML, free-form/AMPscript).
  • VAWP = "View As Web Page" β€” the browser version of the email; relies on the email being rendered/accessible. Blank VAWP is a classic RCA.
  • Preview & Test = render against a DE row + send a proof/test before the real send. Always do it for advisor sends.

🧩 Mnemonics & memory hooks

  • Send flow β†’ "CAESPST": "Calm Advisors Expect Safe Precise Sends, Tracked." (Content, Audience, Exclusions, Send-class, Preview, Send, Track.)
  • Send Classification 3 parts β†’ "S-D-C" = "Sender, Delivery, Compliance." Who / How / Legal.
  • Sender vs Delivery β†’ "Sender = the FACE, Delivery = the TRUCK." Face = From/Reply-to; Truck = IP, domain, footer.
  • 3 send modes β†’ "U-T-T" = "User, Triggered, Transactional." "You Type, Trigger Trips, Trans Talks." (manual / event-fired / API 1:1.)
  • Commercial vs Transactional β†’ "Transactional = no unsubscribe." Statements/OTP must arrive even if they opted out of marketing.
  • A/B β†’ "One knob, small split, winner ships." Change ONE variable, test a slice, send remainder the winner.
  • Content Builder β†’ "TSB = Templates have Slots, Slots hold Blocks." Russian-doll: T βŠƒ S βŠƒ B.

πŸ’€ Skeletons to memorize

Personalized greeting + compliance-safe fallback (Content Builder free-form block / AMPscript):

%%[
  VAR @firstName, @advisor
  SET @firstName = AttributeValue("FirstName")
  SET @advisor   = AttributeValue("AdvisorName")
  IF EMPTY(@firstName) THEN SET @firstName = "Valued Client" ENDIF
]%%
Dear %%=v(@firstName)=%%,
Your advisor, %%=v(@advisor)=%%, has an update on your portfolio.

πŸ” Line by line: - VAR @firstName, @advisor β€” declare the two variables you'll use. - SET @firstName = AttributeValue("FirstName") β€” pull the subscriber's first name from the sendable DE/profile attribute. - SET @advisor = AttributeValue("AdvisorName") β€” pull the advisor name (key for distributed/advisor comms). - IF EMPTY(@firstName) ... ENDIF β€” fallback so a NULL never renders as "Dear ," (looks broken + unprofessional in financial comms). - %%=v(@firstName)=%% β€” output the variable into the HTML body.

Make VAWP work β€” add the View-As-Web-Page link in the email body:

<a href="%%view_email_url%%">View this email in your browser</a>

πŸ” Line by line: - %%view_email_url%% β€” built-in SFMC personalization string that resolves to the hosted web-page version of THIS send. - Put it near the top; if VAWP is blank, the #1 cause is content that only renders with subscriber data the web view can't resolve.

Suppress before send (SQL query activity feeding an exclusion DE):

SELECT s.SubscriberKey, s.EmailAddress
FROM   Send_Audience s
WHERE  s.SubscriberKey NOT IN (SELECT SubscriberKey FROM Global_Optout)
  AND  s.CountryConsent = 'Y'

πŸ” Line by line: - SELECT s.SubscriberKey, s.EmailAddress β€” the minimum a sendable DE needs. - FROM Send_Audience s β€” your raw target population. - NOT IN (SELECT SubscriberKey FROM Global_Optout) β€” drop anyone on the master opt-out list (compliance). - AND s.CountryConsent = 'Y' β€” extra consent gate common in financial services; only keep explicitly-consented records.

πŸ› οΈ In practice (what you would actually click / do)

A) Build & send a user-initiated campaign (full click-path): 1. Email Studio β†’ Content (Content Builder). Click Create β†’ Email Message β†’ Template-based. Pick a template, click into slots, drag blocks in, drop your AMPscript in a free-form/HTML block. 2. Save. Top-right β†’ Preview and Test. In the Preview tab pick a Data Extension and a subscriber row β†’ confirm personalization + fallbacks render. 3. Still in Preview/Test β†’ Send Test tab β†’ enter your address / a test DE β†’ Send the proof. Open it on desktop + mobile + click VAWP link. 4. Back to the email β†’ Send (Guided Send wizard opens). Step Define Properties β†’ name the send. 5. Select Audience: choose the sendable DE / list / filter. Add Exclusion and Suppression Lists here (e.g., Global_Optout, advisor-region suppression). 6. Configure Delivery: pick the Send Classification (this auto-fills Sender Profile + Delivery Profile + Commercial/Transactional). Set subject line, dedupe option. 7. Schedule or Send: Send Now or Schedule (date/time/timezone). Review the summary β†’ Send. 8. Track: Email Studio β†’ Tracking (or Analytics Builder β†’ Email Tracking) β†’ open the job β†’ read Sent / Delivered / Opens / Clicks / Bounces (hard vs soft) / Unsubscribes / Complaints.

B) Set up a native A/B test: - Content Builder β†’ Create β†’ A/B Test (or from a send choose A/B). Pick the ONE variable: Subject Line, From Name, Content, or Send Time/Date. - Build Version A and Version B (differ ONLY by that variable). - Choose the test split % (e.g., 10%/10%, remaining 80% gets winner) and the audience. - Pick winner criteria: highest Open Rate or highest Click-Through Rate. - Set test duration / "Declare Winner by" time β†’ choose auto-send winner to remainder (or manual). - Send. After the window, winner ships to the rest. Tie β†’ Condition A.

C) Triggered vs Transactional (when JD says "advisor comms / API"): - Triggered Send: Email Studio β†’ Interactions β†’ Triggered Sends β†’ create TSD, attach email + send classification, Start/Publish it; it fires per event (e.g., welcome). Subject to unsub/suppression. - Transactional via API: use Transactional Messaging REST API (/messaging/v1/email/messages/{key}) for real-time 1:1 (OTP, statement-ready). No unsub footer required; immediate; tracked via the API events.

D) Sender/Delivery/Classification setup (Admin task): - Email Studio β†’ Admin β†’ Send Management β†’ create Sender Profile (From name/email/reply-to), Delivery Profile (IP, header/footer w/ physical address), then Send Classification binding both + Commercial/Transactional.

🎀 Rapid-fire

  • Q: What's in a Send Classification? A: Sender Profile + Delivery Profile + CAN-SPAM type (Commercial/Transactional). …and in practice: I pick it in the Guided Send "Configure Delivery" step so From-line and footer are correct in one shot.
  • Q: Sender vs Delivery Profile? A: Sender = From/Reply-to (the face); Delivery = IP, sending domain, header/footer (the truck).
  • Q: When Transactional? A: Receipts, OTP, password resets, statement-ready alerts β€” must deliver even to marketing opt-outs; no unsub footer. …and in practice: I'd send these via Transactional API or a TSD with a Transactional classification.
  • Q: 3 ways to send? A: User-Initiated (manual), Triggered (event/TSD), Transactional (REST API, 1:1).
  • Q: Native A/B rules? A: One variable, % test split, winner by open or click rate, remainder gets winner, tie β†’ A.
  • Q: Content Builder hierarchy? A: Template β†’ Slots β†’ Blocks. …and in practice: AMPscript lives in a free-form/HTML block inside a slot.
  • Q: What is VAWP? A: View As Web Page β€” hosted browser version via %%view_email_url%%.
  • Q: How do you test before sending? A: Preview against a DE row, then send a proof/test, check render + VAWP + links on multiple clients. …and in practice: I never skip the proof for advisor/financial sends.
  • Q: Where do exclusions go? A: In Guided Send "Select Audience" β†’ Exclusion + Suppression lists (and pre-built into the sendable DE via SQL).
  • Q: Where do you read results? A: Email Studio Tracking / Analytics Builder β†’ Sent, Delivered, Opens, Clicks, Bounces, Unsubs, Complaints.

⚠️ Gotchas / RCA hooks

  • VAWP is blank. Likely the body renders only with subscriber/DE context the web view can't resolve, an AMPscript error, or content blocked. RCA: open the email, run Preview against a real row, check for AMPscript runtime errors / missing AttributeValue fallbacks, confirm %%view_email_url%% link present; fix the unguarded NULL/personalization.
  • Wrong audience sent. Sent to the raw target, not the suppressed/consented set. RCA: trace the sendable DE back to its SQL/filter, confirm exclusion + suppression lists were attached in Guided Send, check dedupe; in financial services verify consent flag β€” re-pull audience and re-validate before resend.
  • Classification mistake (Commercial vs Transactional). Marketing email sent Transactional (skips unsub β€” CAN-SPAM/consent breach) OR an OTP sent Commercial (gets suppressed, customer locked out). RCA: check the Send Classification used on the job; correct the binding; for compliance breaches log the INC, document RCA, add a validation step / restrict who can send Transactional.
  • From-line / footer wrong. Caused by the wrong Sender/Delivery Profile. RCA: Admin β†’ Send Management β†’ verify the profile fields and the classification it's bound to.
  • Proof looked fine, real send broke. Proof used a hardcoded test row; production rows had NULLs. RCA: preview against MULTIPLE real rows incl. edge cases (empty advisor name) before send.
  • A/B "no winner"/tie confusion. Remember: tie defaults to Condition A, and changing more than one variable invalidates the test.

➑️ Next: C06_Journey_Builder.md

C06 β€” Journey Builder

🎯 Why Coforge cares: the JD is "run email campaigns & journeys, advisor/Distributed-Marketing communications, data accuracy & segmentation, troubleshoot campaign/data/integration failures under SLA" β€” Journey Builder is the orchestration engine where all of that runs and breaks.

🧠 One-screen mental model

A journey is a pipe: contacts enter on the left, flow through activities, and either hit the exit/goal or get filtered out by decisions.

                β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
   ENTRY        β”‚                    JOURNEY CANVAS                          β”‚   GOAL / EXIT
  SOURCE ──────►│  [Wait] ─► [Email] ─► <Decision Split?> ──Yes─► [Email] ─► │──► 🎯 Goal met
  (DE/API/      β”‚                            β”‚                              β”‚    OR ❌ Exit criteria
   SF event/    β”‚                            └──No──► [Update Contact] ─────►│    OR end-of-flow
   CloudPage)   β”‚                                                            β”‚
                β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                  β–² snapshot taken HERE = JOURNEY DATA (frozen for whole run)
                  CONTACT DATA = live, re-read from DEs/Contact model anytime
ENTRY SOURCE Wait / Email Split (decision) Email / Update Update Contact 🎯 Goal / Exit Yes No

Journey Data vs Contact Data β€” the single most-tested practical concept:

Entry @ T0 snapshot taken JOURNEY DATA = FROZEN value at T0, never changes CONTACT DATA = LIVE re-read from DE each step Email/Split reads ONE of these at runtime

πŸ”‘ Core in 60 seconds

  • Anatomy: Entry Source β†’ Activities β†’ Goals/Exit. One entry source per journey version.
  • Entry sources: Data Extension (scheduled batch), API Event (REST fires entry), Salesforce Data Event (MOD/CRM record create/update via Marketing Cloud Connect), CloudPage / Audience / Event.
  • Activities: Messages (Email, SMS), Flow control (Wait, Splits, Join), Update Contact, Custom/Sales & Service (Create/Update SF object β†’ for advisors logging to CRM).
  • Splits: Decision (attribute logic), Engagement (opened/clicked?), Random (% A/B/n), Einstein (AI: STO / engagement freq / split).
  • Journey Data = frozen snapshot at entry. Contact Data = live, re-read every step. Choose deliberately.
  • Re-entry: No re-entry / Re-entry anytime / Re-entry only after exiting.
  • Goal: a metric target (e.g. "advisor completed profile"). Exit criteria: kick contacts out mid-flow (e.g. unsubscribed, became non-compliant).
  • Versioning: you cannot edit a running version. Edit = create a new version β†’ activate β†’ old version goes "Finishing" β†’ drains β†’ "Stopped". New entrants hit the new version.
  • Test mode: dry-run the path with a test contact before activating (no live sends to the real audience source).

🧩 Mnemonics & memory hooks

  • Journey anatomy β†’ "E-A-G-E" = "EAGER": Entry β†’ Activities β†’ Goals β†’ Exit. An eager contact runs the pipe.
  • Entry sources β†’ "DASC" = "Data-Always-Starts-Contacts": Data Extension, API event, Salesforce data event, CloudPage.
  • Splits β†’ "DERE" said as "DEAR-E": Decision, Engagement, Random, Einstein. Dear-E decides who goes where.
  • Flow-control extras β†’ "WJU" = "We Just Update": Wait, Join, Update Contact.
  • Journey vs Contact data β†’ "Frozen Journey, Live Contact": Journey = a photo at the door; Contact = a live CCTV feed.
  • Re-entry β†’ "Never / Always / After": the three doors β€” locked, open, or open-once-you-leave.
  • Versioning β†’ "Running = Read-only": to change it, clone the version.

πŸ’€ Skeletons to memorize

1) Fire an API-event entry (REST) β€” the practical "how do advisors get added?" answer

POST https://YOUR_SUBDOMAIN.rest.marketingcloudapis.com/interaction/v1/events
Authorization: Bearer {access_token}
Content-Type: application/json

{
  "ContactKey": "ADV-100245",
  "EventDefinitionKey": "APIEvent-advisor-onboarding",
  "Data": {
    "AdvisorId": "ADV-100245",
    "FirstName": "Maya",
    "Email": "maya@firm.com",
    "ComplianceCleared": true
  }
}

πŸ” Line by line: - POST .../interaction/v1/events β€” the Journey Builder REST endpoint that injects a contact into a journey. - Authorization: Bearer {access_token} β€” OAuth2 token from your installed package (client credentials). - ContactKey β€” the subscriber's unique key; must already exist or be creatable in the Contact model. - EventDefinitionKey β€” copies from the journey's API Entry config; this is what binds the call to THAT journey. - Data β€” the payload that becomes Journey Data (frozen snapshot) for this run; field names must match the entry-source DE/event schema. - ComplianceCleared β€” financial-services gate value you can split on at entry.

2) Personalize an email with Journey Data vs Contact Data (AMPscript)

%%[
  /* Journey Data = frozen snapshot from the entry payload */
  SET @nameAtEntry = [AdvisorId]              /* or {{Event.DEKey.Field}} in JB binding */

  /* Contact Data = live lookup at send time */
  SET @rows = LookupRows("Ent.Advisor_Master","AdvisorId", @nameAtEntry)
  IF RowCount(@rows) > 0 THEN
    SET @row  = Row(@rows,1)
    SET @tier = Field(@row,"ServiceTier")      /* live value, may have changed since entry */
  ENDIF
]%%
Welcome aboard, advisor %%=v(@nameAtEntry)=%% β€” current tier: %%=v(@tier)=%%

πŸ” Line by line: - SET @nameAtEntry = [AdvisorId] β€” reads the attribute Journey Builder injected at entry (frozen). - LookupRows("Ent.Advisor_Master",...) β€” a live read against the shared (Ent.) Advisor DE β€” this is Contact-data-style behavior. - RowCount > 0 guard β€” never assume the lookup found a row; financial data must be defensive. - Field(@row,"ServiceTier") β€” pulls the freshest tier; if the advisor was upgraded since entry, this shows the new value while @nameAtEntry stays as it was at the door. - The output line proves the contrast in one message: frozen ID + live tier.

3) Bind a Decision Split on Journey Data (the JB expression you'd type)

Decision Split β†’ Path "Compliant"
  WHERE  {{Event.APIEvent-advisor-onboarding.ComplianceCleared}}  EQUALS  true
Default path β†’ "Hold for compliance review"

πŸ” Line by line: - {{Event.<EventDefinitionKey>.<Field>}} β€” the binding syntax for Journey Data inside split criteria. - EQUALS true β€” routes only cleared advisors down the welcome path. - Default path β€” every split needs a catch-all; unmatched advisors are parked, not silently dropped (RCA-friendly).

πŸ› οΈ In practice (what you would actually click / do)

Build the advisor-onboarding journey (click-path):

  1. Journey Builder β†’ New Journey β†’ Build from scratch (Multi-Step).
  2. Drag the Entry Source. For batch: Data Extension, pick Advisor_Onboarding_Entry DE, set Filter (e.g. ComplianceCleared = true), set Schedule (e.g. daily 6am) and re-entry mode. For real-time: drag API Event, define attributes, copy the EventDefinitionKey.
  3. Set re-entry: click the entry source gear β†’ No re-entry for one-time onboarding (an advisor should onboard once).
  4. Drag activities in order: Wait (1 day) β†’ Email ("Welcome + first login") β†’ Wait (2 days) β†’ Decision Split on ComplianceCleared / profile-completed β†’ Yes: Email ("Set up your book of business") β†’ No: Update Contact (flag NeedsComplianceReview = true) + Email to ops.
  5. Configure each Email: click the Email activity β†’ select a Content Builder email β†’ choose send-time personalization; set Sender Profile + Send Classification (commercial vs transactional β€” matters for compliance/CAN-SPAM footer).
  6. Add a Goal: click the flag at top β†’ metric = "Advisor profile completed" with a target %. Add Exit Criteria β†’ "unsubscribed OR ComplianceCleared = false" so non-compliant advisors leave immediately.
  7. Choose Journey vs Contact data: in journey Settings, decide if splits/personalization read the frozen entry snapshot or do live DE lookups. Onboarding usually wants live tier/status β†’ use Contact Data or AMPscript LookupRows.
  8. Validate: click Validate (top bar) β€” JB checks for unconfigured activities, missing content, broken bindings.
  9. Test (Test Mode): Activate dropdown β†’ Test β†’ pick a test contact/DE β†’ JB simulates the path, wait times collapse, no send to the real audience source β€” you watch which path the contact takes and inspect rendered emails.
  10. Activate β†’ confirm version β†’ journey goes Running.

Push a change to a LIVE journey (you CANNOT edit the running one):

  1. Open the journey β†’ Edit β†’ JB auto-creates Version 2 (Draft) β€” Version 1 keeps running untouched.
  2. Make edits in V2 (add a Wait, fix copy, retune a split).
  3. Validate β†’ Test β†’ Activate V2.
  4. On activation: V1 β†’ "Finishing" (current members drain to the end), V2 β†’ "Running" (all new entrants use it). When V1 empties it becomes "Stopped."
  5. To stop entirely: Stop the journey (ejects everyone) vs Pause (holds them in place β€” safer for a hot incident; resume later).

Test mode quick recall: "Test mode = dress rehearsal. Real path, fake send, instant waits."

🎀 Rapid-fire

  • Q: Entry source for advisors created in the CRM? β†’ Salesforce Data Event (via Marketing Cloud Connect) β€” fires on record create/update on the MOD/CRM object. …and in practice: you select the SF object + criteria in the entry source, and Connect must be configured with that business unit.
  • Q: Journey Data vs Contact Data β€” one-liner? β†’ Journey Data is the frozen snapshot at entry; Contact Data is live, re-read each step. …and in practice: if a split must reflect a status that changes mid-journey (e.g. advisor revoked), use Contact Data / live lookup, not the entry snapshot.
  • Q: Can you edit a running journey? β†’ No. Create a new version, activate it; old version drains in "Finishing". …and in practice: I clone to V2, Validate, Test, then Activate β€” zero disruption to in-flight advisors.
  • Q: Four split types? β†’ Decision, Engagement, Random, Einstein (DEAR-E). …and in practice: Decision for attribute logic, Engagement for opened/clicked, Random for A/B, Einstein for AI send-time.
  • Q: Goal vs Exit criteria? β†’ Goal = success metric/target; Exit = condition that removes a contact mid-flow. …and in practice: Exit on unsubscribe OR non-compliant is mandatory in financial services for suppression.
  • Q: Stop vs Pause? β†’ Stop ejects all members (irreversible for them); Pause freezes them in place to resume. …and in practice: during an INC I Pause to stop the bleed without losing journey state, investigate, then resume.
  • Q: Re-entry modes? β†’ No re-entry / Anytime / Only after exiting. …and in practice: onboarding = No re-entry; a recurring nurture = Anytime.
  • Q: How do you inject one contact on demand? β†’ Fire an API Event to /interaction/v1/events with the EventDefinitionKey.
  • Q: Why might a contact not enter? β†’ Doesn't meet entry filter, already in journey (re-entry rule), no matching ContactKey, or in suppression/exclusion list.

⚠️ Gotchas / RCA hooks

  • "Email shows stale data." β†’ You bound Journey Data (frozen) where you needed live. RCA: check whether personalization reads {{Event...}} (frozen) vs an AMPscript live LookupRows. Fix = switch to Contact Data / live lookup.
  • "My edit didn't take effect." β†’ You edited a draft but never activated the new version, or V1 is still "Finishing" so old members see old content. RCA: check version status (Running vs Finishing vs Draft).
  • "Contacts not entering." β†’ Entry filter excludes them, re-entry = No re-entry and they were in before, missing/duplicate ContactKey, schedule not run yet, or stuck in a global suppression/exclusion list. RCA path: Journey Entry Source > history, check DE row count, check Contact Builder for the key, check exclusions.
  • "Advisor got a non-compliant message." β†’ No Exit Criteria for compliance status, or split read frozen data that was compliant at entry but later revoked. RCA: add live exit criteria + use Contact Data for the gate.
  • "API event 400/entry rejected." β†’ EventDefinitionKey mismatch, payload field names don't match entry schema, or token scope missing journeys/automations. RCA: compare payload keys to the entry-source attributes exactly.
  • "Wait never ends / sends bunch up." β†’ Wait at journey end, timezone of Wait-By-Attribute, or activation during a wait window. RCA: inspect Wait config + journey activation time.
  • "Can't tell who's where." β†’ Use Journey Builder > journey > History / contact path and Journey Analytics to see per-activity counts; ties directly to SLA reporting on campaign failures.
  • Distributed Marketing note: advisor-sent journeys originate from Distributed Marketing / Sales & Service Cloud quick-send; the journey still runs in MC but entry comes from the advisor's CRM action β€” know that boundary for integration RCA.

➑️ Next: C07_Validation_Testing_Deployment.md

C07 β€” Campaign Validation, Testing, Preview & Deployment (PRACTICAL CORE)

🎯 Why Coforge cares: the JD literally lists "campaign validation, testing, preview & deployment" β€” a botched advisor send in financial services is a compliance event, so they need someone who can prove a send is correct before it leaves, not just describe it.

🧠 One-screen mental model

        BUILD                 VALIDATE (pre-send QA)              DEPLOY / SEND
   β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”     β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”   β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
   │ Email +      │     │ 1 PREVIEW & TEST (real DE row) │   │ Promote dev→QA→prod│
   β”‚ AMPscript +  β”‚ ──► β”‚ 2 Render test (Litmus)        │──►│ via Package Manager β”‚
   β”‚ Dynamic Cont.β”‚     β”‚ 3 Links / UTM                  β”‚   β”‚ + folder/naming govβ”‚
   β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜     β”‚ 4 Audience row count          β”‚   β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
          β–²             β”‚ 5 Compliance: unsub/footer/SC β”‚             β”‚
          β”‚             β”‚ 6 VAWP / View As Web Page     β”‚             β–Ό
   β”Œβ”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”     β”‚ 7 Proof / Test send           β”‚   β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
   β”‚ Git versionedβ”‚     β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜   β”‚ Scheduled / triggered
   β”‚ HTML/AMP/SSJSβ”‚            FAIL β—„β”€β”€β”€β”€β”˜  PASS ──────────► β”‚ send to PROD audience
   β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜         (RCA, fix, re-run)              β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

πŸ”‘ Core in 60 seconds

  • Preview & Test tab (inside the email in Content Builder) = your #1 weapon: pick a real subscriber / DE row, see AMPscript + dynamic content resolved with actual data, not raw code.
  • Test Send (a.k.a. proof) goes to you / a test DE, runs the real send-time engine (so it catches AMPscript errors a preview can miss).
  • Render testing = Litmus / Email on Acid: check Outlook (worst client) and dark mode.
  • Audience verification = run the SQL / check DE row count before send; a wrong count = wrong audience.
  • Compliance gates (finance): unsub link, physical address footer, correct sender/CAN-SPAM classification, suppression applied.
  • VAWP = "View as Web Page" link must render (breaks if DE/email/sender is moved/overwritten after send).
  • Deploy path: dev BU β†’ QA BU β†’ prod BU. Move assets with Package Manager (modern) / Deployment Manager (legacy AppExchange). Keep source of truth in Git.

🧩 Mnemonics & memory hooks

  • QA checklist = "PRLACVP" β†’ say it as "PuRe LACK of VP" (no VP signs off if QA fails):
  • Preview with real data β†’ Render (Litmus/Outlook/dark) β†’ Links & UTM β†’ Audience count β†’ Compliance (unsub/footer/classification) β†’ VAWP β†’ Proof/test send.
  • Compliance four = "FUSS" β†’ make a FUSS before any finance send: Footer (address) Β· Unsub link Β· Sender/classification Β· Suppression applied.
  • Deploy promotion = "D-Q-P, Package, Pin" β†’ Dev β†’ QA β†’ Prod, move via Package Manager, Pin it in Git. ("DQP" sounds like "dee-cue-pee, ship it clean.")
  • Render killers = "OLD" β†’ Outlook (Word engine) Β· Length/clipping (Gmail 102KB) Β· Dark mode. "OLD clients break new emails."

πŸ’€ Skeletons to memorize

1. Defensive AMPscript so Preview/Test never hard-fails on a bad row

%%[
  VAR @firstName, @advisor
  SET @firstName = AttributeValue("FirstName")
  IF EMPTY(@firstName) THEN SET @firstName = "Valued Client" ENDIF
  SET @advisor = Lookup("Advisors","AdvisorName","ClientID", AttributeValue("ClientID"))
  IF EMPTY(@advisor) THEN SET @advisor = "your Gap Financial team" ENDIF
]%%
Hello %%=v(@firstName)=%%, your advisor %%=v(@advisor)=%% has an update.

πŸ” Line by line: - VAR @firstName, @advisor β€” declare variables up front so the block is readable. - SET @firstName = AttributeValue("FirstName") β€” pull the field from the current DE row being previewed. - IF EMPTY(...) ... ENDIF β€” fallback default so an empty cell doesn't show a blank or error during QA. - Lookup("Advisors",...) β€” fetch the advisor name from a related DE by ClientID; the realistic finance case. - second IF EMPTY β€” fallback if the lookup misses, so no row breaks the proof send. - %%=v(@firstName)=%% β€” output the resolved value; this is exactly what Preview shows per chosen row.

2. Audience row-count + suppression check SQL (run in Automation Studio / Query before send)

SELECT COUNT(*) AS SendCount
FROM   Campaign_Q2_Advisors aud
WHERE  aud.OptInStatus = 'Subscribed'
  AND  aud.SubscriberKey NOT IN (SELECT SubscriberKey FROM Global_Suppression)
  AND  aud.SubscriberKey NOT IN (SELECT SubscriberKey FROM Holdout_Control);

πŸ” Line by line: - SELECT COUNT(*) AS SendCount β€” the single number you compare to the expected audience size. - FROM Campaign_Q2_Advisors β€” your built send audience DE. - OptInStatus = 'Subscribed' β€” only consentable rows (consent matters hard in financial services). - NOT IN (... Global_Suppression) β€” strip anyone on the master suppression list. - NOT IN (... Holdout_Control) β€” exclude the holdout/control group so the test stays valid. - Eyeball the result vs the brief: if 50k expected and 12k returned, stop and RCA before sending.

3. Folder + naming governance pattern (so QA/Deploy is traceable)

Content Builder / Data Extensions naming:
  [BU]_[Domain]_[Campaign]_[Type]_[YYYYMMDD]_[vN]
  e.g.  FS_Advisor_Q2Review_Email_20260620_v3

Folder tree:
  πŸ“ 01_Dev  β†’ πŸ“ 02_QA  β†’ πŸ“ 03_Prod  β†’ πŸ“ 99_Archive

πŸ” Line by line: - [BU] β€” business unit / brand (here FS = Financial Services) so cross-BU promotes stay clear. - [Domain]_[Campaign] β€” who it's for and which campaign; searchable in 6 months. - [Type] β€” Email / DE / Query / Journey, so asset type is obvious. - [YYYYMMDD]_[vN] β€” date + version; the version is what you reconcile against Git. - The Dev β†’ QA β†’ Prod β†’ Archive folders give a visual promotion path and prevent sending a dev asset to prod.

πŸ› οΈ In practice (what you would actually click / do)

A. Preview & Test against a real row (the LTM-gap fix β€” say this out loud) 1. Email Studio / Content Builder β†’ open the email β†’ top tabs β†’ Preview and Test. 2. Preview sub-tab β†’ "Preview using" β†’ choose Data Extension β†’ pick your send DE β†’ select a specific row (e.g. a row with a NULL advisor) β†’ confirm AMPscript + dynamic content render correctly. 3. Cycle 3–5 rows: a populated row, an empty-field row, a suppression-edge row. 4. Switch the dynamic-content / decision rules preview to confirm each variant (e.g. "Premier" vs "Standard" client block) fires for the right segment.

B. Test / Proof send (catches send-engine-only errors) 1. Same screen β†’ Test Send sub-tab. 2. Set From / Sender Profile and Send Classification (must be the correct commercial vs transactional one β€” finance auditors check this). 3. Choose a test data extension (so personalization runs on real-shaped data), add your inbox + QA distribution list. 4. Send β†’ open in Gmail, Outlook desktop, iOS Mail, toggle dark mode. 5. If AMPscript throws here but previewed fine β†’ it's a send-time function issue (e.g. Lookup on a DE the send context can't see) β†’ fix and re-proof.

C. Render testing 1. Either forward the proof to a Litmus/Email on Acid seed address, or paste HTML into their app. 2. Prioritize Outlook (Windows) β€” it uses Word's rendering engine; check tables/VML buttons, then dark mode inversion of logos/text. 3. Check Gmail clipping (>102KB) β€” trim inline CSS/comments if clipped.

D. Link & UTM check 1. In Preview, click every link (or use Litmus link validation) β†’ no http:// placeholders, no broken %%=RedirectTo()=%%. 2. Confirm UTM params on each CTA (source/medium/campaign) so reporting/attribution is right. 3. Verify the unsub %%unsub_center_url%% / profile-center link and the physical-address footer are present.

E. Audience verification 1. Automation Studio β†’ SQL Query Activity (or Query Studio) β†’ run the row-count + suppression SQL above β†’ compare to the campaign brief. 2. In the DE record view, confirm row count and spot-check 5 rows for data accuracy. 3. Confirm global/CAN-SPAM suppression and holdout were applied (this is the data-accuracy pillar in the JD).

F. VAWP / "View as Web Page" 1. After proof, click the "View as a Web Page" link in the email β†’ it must render fully. 2. Remember it breaks if you move/rename/overwrite the email, sender profile, or DE after send β€” so freeze assets post-send.

G. Deploy / promote (dev β†’ QA β†’ prod BU) 1. Build & QA in the Dev BU, get sign-off in QA BU. 2. Setup β†’ Package Manager β†’ Create Package β†’ add assets (email, DEs, automations, journeys, content blocks) β†’ Validate β†’ Deploy to the target (prod) BU. 3. (Legacy alt: Deployment Manager AppExchange app for BU-to-BU asset copy.) 4. Re-point the deployed email to the prod DEs/sender profile, re-run a prod proof, then schedule/activate the send or journey. 5. Commit the final HTML / AMPscript / SSJS to Git (branch per release, tag the version that matches the asset name) β€” that's your rollback + audit trail.

H. SLA / critical-send readiness - Keep a one-page QA checklist (PRLACVP) attached to the deploy ticket; reviewer signs each line. - For critical sends, do a canary: send to a small internal seed segment first, watch deliverability/rendering, then release the full audience.

🎀 Rapid-fire

  1. Q: Preview vs Test Send β€” difference? A: Preview renders against a chosen DE row in the UI; Test Send actually runs the send engine to a test DE/inbox. …and in practice: I always do both β€” preview catches layout/data, the proof catches send-time AMPscript (Lookup/HTTPGet) failures.

  2. Q: An advisor's name shows blank in preview β€” what now? A: The DE field is NULL or the lookup missed. …and in practice: add an IF EMPTY() fallback in AMPscript, re-preview that exact row, then re-proof.

  3. Q: How do you confirm you're sending to the right people? A: Run a COUNT(*) SQL with opt-in + suppression + holdout filters and compare to the brief; spot-check rows. …and in practice: I never trust the build alone β€” wrong count = stop and RCA before send.

  4. Q: Which email client do you test hardest and why? A: Outlook (Windows) β€” Word rendering engine breaks modern CSS; plus dark mode. …and in practice: I seed Litmus, fix with table layout/VML buttons, re-check.

  5. Q: What is VAWP and why does it break? A: "View as Web Page"; breaks when the email/DE/sender profile is moved or overwritten after send. …and in practice: I freeze and archive send assets and never overwrite a sent DE.

  6. Q: How do you promote a campaign from dev to prod? A: Package Manager creates a validated package of assets and deploys to the target BU; re-point to prod data, re-proof, schedule. …and in practice: final code goes to Git with a version tag matching the asset name.

  7. Q: Compliance items you check before any finance send? A: FUSS β€” Footer address, Unsub link, Sender/classification, Suppression applied. …and in practice: these are non-negotiable sign-off lines on the deploy ticket.

  8. Q: A critical send is due in 1 hour β€” how do you de-risk it? A: Run the PRLACVP checklist, then a canary to an internal seed before full release. …and in practice: if the canary renders/deliverers clean, I release; if not, I hold and RCA β€” SLA respects correctness.

⚠️ Gotchas / RCA hooks

  • "It previewed fine but errored on send." β†’ Preview β‰  send context. RCA: re-run as Test Send; check Lookup/LookupRows target DEs are reachable in the send BU; check publication/shared-DE scope.
  • Wrong audience count. β†’ RCA: re-open the SQL/filter, check JOIN/NOT IN logic and that suppression + holdout actually applied; verify the automation ran on fresh data (stale import = wrong count).
  • Links broken / wrong UTM. β†’ RCA: search HTML for hard-coded http://, unresolved %%=RedirectTo()=%%, missing ?utm_; re-validate in Litmus link checker.
  • VAWP shows "temporarily unavailable." β†’ RCA: the email, sender profile, or DE was moved/overwritten/deleted after send. Fix: restore/avoid post-send edits; archive sent assets read-only.
  • Outlook layout collapses / dark-mode logo disappears. β†’ RCA: relying on modern CSS/transparent PNGs. Fix: table layout, bulletproof buttons, dark-mode-safe logo background.
  • Deployed to prod but still points at dev DEs. β†’ RCA: post-deploy re-pointing missed. Fix: after Package Manager deploy, re-bind email to prod DEs/sender and re-proof in prod before scheduling.
  • No rollback when a send goes wrong. β†’ RCA: code lived only in SFMC UI. Fix: Git-version HTML/AMPscript/SSJS with release tags so you can restore the last good version fast (SLA recovery).

➑️ Next: C08_Distributed_Marketing.md

C08 β€” Distributed Marketing & Advisor Communications (NEW β€” JD-critical)

🎯 Why Coforge cares: the JD explicitly names "Distributed Marketing / advisor communications" and "MOD (CRM)" β€” this is how a bank advisor sends an approved, compliant SFMC email to their own client from inside Sales/Service Cloud, with brand + compliance locked down centrally. Nail this and you own the headline differentiator.

🧠 One-screen mental model

  CENTRAL (You = Marketing Cloud admin)          LOCAL (Advisor in CRM)
 β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”      β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
 β”‚  Email Studio: build approved email   β”‚      β”‚  Sales/Service Cloud record  β”‚
 β”‚  Journey Builder: wrap in a Journey   β”‚      β”‚  (Contact / Lead / Campaign) β”‚
 β”‚  Content Builder: brand + legal lock  β”‚      β”‚                              β”‚
 β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜      β”‚  β–Έ Quick Send  (1 message)   β”‚
                 β”‚ make Journey AVAILABLE        β”‚  β–Έ Add to Journey (series)   β”‚
                 β”‚ to Distributed Marketing      β”‚  β–Έ personalize + APPROVE      β”‚
                 β–Ό                               β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
        β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”                                β”‚ advisor clicks SEND
        β”‚  DM Managed Package   │◀── Marketing Cloud Connect ───▢│
        β”‚  (installed in CRM)   β”‚     (the account-level link)    β”‚
        β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜                                 β–Ό
                   β”‚ writes sender into          β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
                   β–Ό  Entry/Event DE             β”‚ Journey fires in Marketing    β”‚
        sendFromName / sendFromEmail  ──────────▢│ Cloud β†’ email sends as ADVISOR β”‚
                                                 β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                                                                 β”‚ opens/clicks/sends
                                                                 β–Ό
                                                   Tracking flows BACK to CRM
                                                   (Campaign Member / Individual Email Result)
  • Central builds & controls. Local picks, personalizes, approves, sends. Tracking returns.

πŸ”‘ Core in 60 seconds

  • What DM is: lets non-marketers (advisors, agents, franchisees) in Sales/Service Cloud send pre-approved SFMC campaigns to their own Contacts/Leads β€” central keeps brand + compliance.
  • Two send modes: Quick Send = one single-message journey, ad-hoc. Add to Journey / Campaign Send = put many members into a multi-step journey (welcome/drip).
  • Plumbing (3 pieces): DM Managed Package (installed in CRM) + Marketing Cloud Connect (the account link) + Journey Builder (every DM send is really a Journey).
  • Sender identity: the email sends as the advisor via sendFromName / sendFromEmail fields in the Entry (Event) Data Extension; Sender Profiles can control this org-wide.
  • Approval gate: advisor must review β†’ personalize β†’ approve campaign members before the send fires. That's the human compliance checkpoint.
  • Permissions: Admin = link journeys to campaigns + org defaults; Standard = personalize + approve + send. Granted via permission set licenses / custom permissions in CRM.
  • Tracking: opens/clicks/sends flow back to CRM (Campaign Member tracking / Individual Email Results) through the MC Connect API user.
  • FinServ fit: advisor-to-client comms at scale, centrally compliant β€” exactly what a bank/insurer wants (advisor adds the human touch, legal can't be broken).

🧩 Mnemonics & memory hooks

  • The 3 plumbing pieces β€” "PCJ" β†’ Package (managed), Connect (Marketing Cloud Connect), Journey (Builder). Hook: "Peanut-butter & Jelly Connects two clouds."
  • What an advisor does β€” "P-A-S-S" β†’ Pick journey β†’ Add members / personalize β†’ Submit for approval β†’ Send. Hook: an advisor needs a PASS to talk to clients.
  • DM value prop β€” "Central Brain, Local Hands" β†’ strategy/compliance central, the personal relationship local. Hook: one brain, many hands.
  • Sender fields β€” "FROM = Name + Email" β†’ sendFromName + sendFromEmail in the Entry DE. Hook: the advisor's face on a corporate letter.
  • Quick Send vs Journey β€” "1 vs Many" β†’ Quick Send = 1 single-message journey; Add-to-Journey = many steps. Hook: Quick = one quick tap.

πŸ’€ Skeletons to memorize

Entry / Event Data Extension (the sender + recipient fields DM needs):

Entry Data Extension columns (minimum)
  ContactKey        -> who the email goes to (advisor's client)
  EmailAddress      -> recipient email
  sendFromName      -> "Priya Sharma, Wealth Advisor"   (shows as From name)
  sendFromEmail     -> priya.sharma@bank.com            (shows as From address)
  FirstName / ...   -> personalization fields for AMPscript

πŸ” Line by line: - ContactKey β€” the subscriber identity; DM routes the message to this advisor's specific client. - EmailAddress β€” the recipient's email; the Journey's sendable DE keys off this. - sendFromName β€” what the client sees as the sender's display name β€” this is how it sends "as the advisor," not "as the bank." - sendFromEmail β€” the reply/from address; pair with a verified Sender Profile so it's deliverable + on-brand. - FirstName etc. β€” feed your AMPscript personalization so each advisor's note still feels 1:1.

AMPscript greeting that keeps the advisor's personal voice (FinServ-safe):

%%[
  VAR @first, @advisor
  SET @first   = AttributeValue("FirstName")
  SET @advisor = AttributeValue("sendFromName")
  IF EMPTY(@first) THEN SET @first = "there" ENDIF
]%%
Dear %%=v(@first)=%%, a quick note from %%=v(@advisor)=%%.

πŸ” Line by line: - VAR β€” declare variables up front (your GAP habit β€” keeps templates readable). - SET @first = AttributeValue("FirstName") β€” pull the client's first name from the Entry DE. - SET @advisor = AttributeValue("sendFromName") β€” reuse the DM sender field so the body matches the From name. - IF EMPTY(... ) THEN ... "there" β€” defensive default so a blank name never prints "Dear ," (a deliverability/compliance embarrassment). - The greeting line renders one personalized note per advisor β€” central template, local voice.

πŸ› οΈ In practice (what you would actually click / do)

A) Central admin β€” make a campaign available to advisors (one-time + per-campaign): 1. Install the DM managed package into Sales/Service Cloud: log out of MC β†’ paste the managed package install URL β†’ choose "Install for Admins/specific profiles." 2. Confirm Marketing Cloud Connect is configured (the MC Connect API user links the CRM org ↔ MC account). Without this, DM has no pipe. 3. In Marketing Cloud β†’ Journey Builder, build the journey using an Entry Source = Data Extension whose schema includes ContactKey, EmailAddress, sendFromName, sendFromEmail. 4. Mark the journey for DM: in the journey settings choose the Quick Send re-entry mode β€” Re-entry at any time (resend allowed) or Re-entry only after exiting. Activate the journey. 5. In CRM (Distributed Marketing app) β†’ link the active MC journey to a Salesforce Campaign (Admin permission). This is what surfaces it to advisors. 6. Lock the brand: email built in Content Builder with locked regions / legal footer so advisors edit only the allowed blocks.

B) Advisor β€” Quick Send (single message, e.g. a market-update or birthday note): 1. Open a Contact/Lead in Sales Cloud β†’ click the Quick Send action (DM component on the page layout). 2. Pick the approved single-message journey β†’ personalize the allowed fields β†’ Send. The email goes out from the advisor via sendFromName/Email.

C) Advisor β€” bulk into a Journey (welcome/drip): 1. Open the linked Salesforce Campaign β†’ DM component shows Campaign Members. 2. Run the "Campaign Send" workflow β†’ review members β†’ approve β†’ members enter the multi-step MC journey.

D) Validate / test / deploy (the part you fumbled before β€” be specific): - Preview & seed: in Journey Builder use the email Preview with a test contact row; send a test send to a seed list before the journey goes live. - Render test: Content Builder "Validate" / Litmus-style preview for inbox rendering + link check. - Personalization test: put a fake advisor row in the Entry DE with sendFromName/Email filled β†’ confirm the From + greeting resolve. - Tracking check: after a test, open the CRM Contact / Campaign β†’ confirm Individual Email Result / Campaign Member activity wrote back. - Deploy: activate journey in MC, link to Campaign in CRM, confirm the Quick Send button appears on the advisor's page layout for the right profile.

🎀 Rapid-fire

  • Q: In one line, what is Distributed Marketing? A: Lets CRM users send pre-approved, brand-controlled SFMC emails/journeys to their own contacts. …and in practice: I link an active MC journey to a Salesforce Campaign so it shows up as a Quick Send button on the advisor's record.
  • Q: Quick Send vs Add-to-Journey? A: Quick Send = one single-message journey, ad-hoc; Add-to-Journey/Campaign Send = many members into a multi-step journey. …and in practice: Quick Send for a one-off market note, Campaign Send for a welcome series.
  • Q: What three components make DM work? A: DM managed package + Marketing Cloud Connect + Journey Builder (mnemonic PCJ).
  • Q: How does the email send "as the advisor"? A: sendFromName / sendFromEmail in the Entry (Event) DE; org-wide control via Sender Profiles. …and in practice: I populate those columns from the running user so each send carries the advisor's name.
  • Q: Where's the compliance gate? A: The advisor must approve campaign members before send, and central locks the template/legal regions. Nothing un-approved or off-brand goes out.
  • Q: Does DM need Marketing Cloud Connect? A: Yes β€” it's the account-level link (via the MC Connect API user) between CRM and Marketing Cloud.
  • Q: How is a DM send tracked? A: Opens/clicks/sends flow back to CRM as Individual Email Results / Campaign Member tracking via the API user. …and in practice: I verify the writeback on the Contact's activity after a test.
  • Q: Why do financial-services firms love DM? A: Advisor-to-client personalization at scale with central brand + compliance β€” the advisor adds the human touch, legal can't be broken.
  • Q: Admin vs Standard permission? A: Admin links journeys↔campaigns + sets org defaults; Standard personalizes, approves, and sends.

⚠️ Gotchas / RCA hooks

  • "Quick Send button missing for an advisor." β†’ RCA: DM permission set license / custom permission not assigned, or the DM action not on that page layout / profile. Fix in CRM Setup.
  • Email sent as the brand, not the advisor. β†’ RCA: sendFromName/sendFromEmail empty in the Entry DE, or Sender Profile overriding. Check the DE row + journey config.
  • Journey not appearing in the DM app. β†’ RCA: journey not Activated, or not linked to a Salesforce Campaign (Admin step skipped).
  • No tracking writeback to CRM. β†’ RCA: Marketing Cloud Connect API user broken / token expired, or Campaign Member tracking not enabled in MC Connect settings.
  • Sender email bounces / lands in spam. β†’ RCA: sendFromEmail domain not authenticated (SAP / SPF-DKIM). FinServ: never let advisors free-type unverified from-addresses β€” constrain via Sender Profiles.
  • Compliance leak (advisor edited a locked legal block). β†’ RCA: Content Builder locked regions not set; re-lock and restrict editable blocks; reinforce the approval step.
  • Wrong client list / data accuracy. β†’ RCA: Entry DE keyed on stale ContactKey; tie DM to a governed, freshly-synced segment, not an ad-hoc upload. (Ties to JD "data accuracy & segmentation.")

➑️ Next: C09_APIs_and_Integrations.md

C09 β€” SFMC APIs & Integrations

🎯 Why Coforge cares: the JD wants someone who can fire journeys/upsert data via SFMC APIs, run Marketing Cloud Connect with the MOD/CRM system, and do RCA on integration failures (401 vs 403, expired tokens) under SLA β€” for advisor/financial-services comms.

🧠 One-screen mental model

                 β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
   Installed     β”‚  Installed Package           β”‚
   Package  ───▢ β”‚  ClientID + ClientSecret     β”‚
   (Setup)       β”‚  + Auth/REST/SOAP base URIs  β”‚
                 β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                                β”‚ POST /v2/token
                                β”‚ grant_type=client_credentials
                                β–Ό
                 β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
                 β”‚  ...auth.marketingcloudapis  β”‚
                 β”‚  returns:                    β”‚
                 β”‚   access_token (~20 min)  β”‚
                 β”‚   rest_instance_url          β”‚
                 β”‚   soap_instance_url          β”‚
                 β””β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”˜
                         β”‚ Bearer token β”‚
            β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”     β”Œβ”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
            β”‚  REST          β”‚     β”‚  SOAP            β”‚
            β”‚ ...rest.mc...  β”‚     β”‚ ...soap.mc...    β”‚
            β”‚ journeys/eventsβ”‚     β”‚ DE CRUD / admin  β”‚
            β”‚ transactional  β”‚     β”‚ subscriber       β”‚
            β”‚ assets/dataev. β”‚     β”‚ WSProxy          β”‚
            β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜     β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

  CRM/MOD  ──Marketing Cloud Connect──▢  Synchronized DEs
  (Sales/Service Cloud)                  + Salesforce Data Events
Installed Package ID + Secret /v2/token access_token ~20 min (short-lived) REST: journeys, events, assets SOAP: DE CRUD, subscriber, admin POST Bearer
CRM / MOD (Sales/Service Cloud) Marketing Cloud Connect (MCC) Synchronized DEs + Data Events

πŸ”‘ Core in 60 seconds

  • Two APIs, one token. Auth once at /v2/token, use the SAME access_token (Bearer) for BOTH REST and SOAP.
  • REST = modern/JSON/fast β†’ journeys, events, transactional messaging, assets, contacts, data events (rowset upsert).
  • SOAP = legacy/XML/powerful β†’ Data Extension CRUD, subscriber, admin, retrieves, anything WSProxy. AMPscript's WSProxy/RetrieveSalesforceObjects ride SOAP under the hood.
  • OAuth 2.0 client_credentials (server-to-server): no user login, no refresh token. Token is short-lived (~20 min) β€” read expires_in from the response, refresh proactively, don't hardcode the number. (Legacy v1 /requestToken was ~1 hour β€” don't confuse the two.)
  • account_id = MID. Pass it in the token request to act on a specific Business Unit.
  • Base URLs come FROM the token response (rest_instance_url, soap_instance_url) β€” never hardcode the subdomain.
  • MCC links CRM (MOD) ↔ SFMC: Synchronized DEs pull CRM objects; Salesforce Data Events trigger journeys from CRM record changes.
  • Fire a journey: POST /interaction/v1/events with ContactKey + EventDefinitionKey.

🧩 Mnemonics & memory hooks

  • REST vs SOAP β†’ "REST takes a JET, SOAP washes the DASH"
  • JET = Journeys, Events/assets, Transactional β†’ REST.
  • DASH = Data extensions, Admin, Subscriber, (WSProxy) Handling β†’ SOAP.
  • OAuth flow β†’ "P-T-T-C": Package β†’ Token β†’ Twenty (min) β†’ Call. "Pack a Token that lasts Twenty, then Call."
  • Token response fields β†’ "A.R.S.": Access_token, Rest_instance_url, Soap_instance_url. (Cover your ARS β€” grab all three.)
  • Error codes β†’ "401 = who? / 403 = no!"
  • 401 Unauthorized = bad/expired token (identity unknown). 403 Forbidden = valid token, wrong scope/MID (known but blocked).
  • Fire-journey payload β†’ "CED": ContactKey, EventDefinitionKey, Data.

πŸ’€ Skeletons to memorize

1) Get the token (server-to-server)

POST https://SUBDOMAIN.auth.marketingcloudapis.com/v2/token
Content-Type: application/json

{
  "grant_type": "client_credentials",
  "client_id": "xxxxxxxxxxxxxxxx",
  "client_secret": "yyyyyyyyyyyyyyyy",
  "account_id": "7280000"
}

πŸ” Line by line: - POST .../v2/token β€” the OAuth2 auth endpoint; subdomain comes from your Installed Package's Auth Base URI. - Content-Type: application/json β€” payload is JSON (not form-encoded). - grant_type: client_credentials β€” server-to-server flow; no human login, no refresh token. - client_id / client_secret β€” the credentials generated by the Installed Package (treat secret like a password). - account_id β€” the MID (Business Unit) you want to act in; omit to use the package's default BU.

Response gives you access_token, rest_instance_url, soap_instance_url, and expires_in (short-lived, ~20 min β€” read it, don't hardcode).

2) Fire a journey entry event (REST)

POST https://SUBDOMAIN.rest.marketingcloudapis.com/interaction/v1/events
Authorization: Bearer ACCESS_TOKEN
Content-Type: application/json

{
  "ContactKey": "advisor_00482",
  "EventDefinitionKey": "APIEvent-quarterly-statement",
  "Data": {
    "FirstName": "Priya",
    "PortfolioId": "P-99213",
    "StatementUrl": "https://secure.bank/stmt/P-99213"
  }
}

πŸ” Line by line: - POST .../interaction/v1/events β€” the endpoint that injects a contact into a journey. - Authorization: Bearer ACCESS_TOKEN β€” the token from step 1; required on every REST call. - ContactKey β€” the subscriber identifier (matches your DE/Contact key, e.g. advisor or client ID). - EventDefinitionKey β€” copy from the journey's API Entry event; this is which journey to fire. Wrong/typo'd key β†’ HTTP 400. - Data {} β€” the event payload; fields must match the journey's Entry Source DE attributes for personalization (FirstName, PortfolioId…). - Success = 201 with an eventInstanceId; inactive/missing contact or bad key = 400.

3) Upsert rows into a DE (REST data events / rowset)

POST https://SUBDOMAIN.rest.marketingcloudapis.com/hub/v1/dataevents/key:AdvisorMaster/rowset
Authorization: Bearer ACCESS_TOKEN
Content-Type: application/json

[
  { "keys": { "AdvisorId": "A-1001" },
    "values": { "Email": "p@bank.com", "Tier": "Platinum", "OptStatus": "Subscribed" } }
]

πŸ” Line by line: - .../hub/v1/dataevents/key:AdvisorMaster/rowset β€” upsert into the DE whose external key is AdvisorMaster (use key: for external key). - Body is an array β€” you can upsert many rows in one call (batches well; great for sync jobs). - keys {} β€” the DE's primary key(s); matched row is updated, unmatched row is inserted (true upsert). - values {} β€” the non-key fields to write. - Returns 2xx per accepted rowset; primary key MUST exist on the DE or it errors.

πŸ› οΈ In practice (what you would actually click / do)

A) Create the Installed Package (one-time, where credentials come from) 1. Setup (top-right gear/avatar) β†’ Platform Tools β†’ Apps β†’ Installed Packages β†’ New. 2. Name it (e.g. MOD-Integration), Save β†’ Add Component β†’ API Integration β†’ Server-to-Server. 3. Tick scopes you need: Journeys (Read/Execute), Data Extensions (Read/Write), Email (Send), Automations, etc. Set the default Business Unit (MID). 4. Save β†’ it generates Client ID, Client Secret, Auth/REST/SOAP Base URIs. Copy them into a vault (never in email/code).

B) Postman flow (the hands-on demo to describe in interview) 1. Get token: new request β†’ POST {{authUri}}/v2/token, Body β†’ raw JSON with grant_type/client_id/client_secret/account_id. Send β†’ copy access_token, rest_instance_url. - Pro move: in the Tests tab set pm.environment.set("token", pm.response.json().access_token) so it auto-saves; reuse as {{token}}. 2. Fire a journey: POST {{restUri}}/interaction/v1/events, Authorization β†’ Bearer Token β†’ {{token}}, body = the CED payload. Expect 201 + eventInstanceId. 3. Upsert DE rows: POST {{restUri}}/hub/v1/dataevents/key:AdvisorMaster/rowset, same Bearer header, array body. Verify in Email Studio β†’ Subscribers β†’ Data Extensions β†’ AdvisorMaster β†’ Records.

C) Wire the journey so the event works 1. Journey Builder β†’ Create β†’ Multi-step, Entry Source = API Event (or Salesforce Data event for CRM-driven). 2. Click the entry β†’ set the Entry Source DE (the schema your Data{} maps to) β†’ copy the generated EventDefinitionKey β†’ paste into your POST. 3. Activate the journey (an API event journey must be Running or events 400/queue silently).

D) Marketing Cloud Connect (CRM/MOD ↔ SFMC) 1. Installed in the CRM org as a managed package; connect SFMC via a dedicated integration user. 2. Synchronized Data Sources (Contact Builder β†’ Data Sources) pull CRM objects (Contact, Lead, custom Advisor obj) into Synchronized DEs. 3. Salesforce Data events in Journey Builder let a CRM record change (e.g. "Advisor status = Active") enter a journey β€” no custom code. 4. Send-from-CRM: marketers send Email Studio emails to CRM Reports/Campaigns; sends/opens/clicks flow back to CRM activity.

E) RCA when an integration breaks (the support-model answer) - Reproduce the failing call in Postman with a fresh token first β€” rules out expiry instantly. - Read the HTTP code (401/403/400/429/5xx), check the integration user's scopes + MID, then check the payload/key mismatch.

🎀 Rapid-fire

  1. Q: REST or SOAP to update a Data Extension? A: SOAP (or REST data events/rowset for upsert) β€” SOAP owns DE/subscriber/admin CRUD. …and in practice: for a bulk sync I'd POST /hub/v1/dataevents/key:DE/rowset with an array; for legacy/AMPscript I'd use WSProxy against SOAP.
  2. Q: How long is an access token valid? A: short-lived β€” ~20 minutes (read expires_in, don't hardcode); client_credentials has no refresh token β€” request a new one. (Legacy v1 /requestToken was ~1 hour.) …and in practice: I store the token + expiry timestamp and re-auth when <2 min remain.
  3. Q: Which grant type for a backend integration? A: client_credentials (server-to-server), no user interaction.
  4. Q: Endpoint to drop a contact into a journey? A: POST /interaction/v1/events with ContactKey + EventDefinitionKey. …and in practice: EventDefinitionKey is copied from the journey's API Entry event; journey must be Running.
  5. Q: Where do REST/SOAP base URLs come from? A: the token response (rest_instance_url, soap_instance_url) β€” tied to your tenant subdomain; don't hardcode.
  6. Q: 401 vs 403? A: 401 = missing/expired/invalid token; 403 = valid token but lacks scope or wrong MID. …and in practice: 401 β†’ re-auth; 403 β†’ edit the Installed Package scopes / fix account_id.
  7. Q: How does CRM data drive a journey without code? A: Marketing Cloud Connect β†’ Salesforce Data event entry source on a Synchronized DE.
  8. Q: Send to 100 contacts in one journey call? A: use the Batch event (/interaction/v1/events/batch) β€” up to 100 contacts per request.
  9. Q: What's the MID and where do I pass it? A: the Business Unit ID; pass as account_id in the token request to scope the token to that BU.

⚠️ Gotchas / RCA hooks

  • Expired token (401): symptom = worked earlier, dead now (token aged out after ~20 min). Fix: re-fetch token; in code re-auth on any 401 and retry once.
  • 403 Forbidden: token is fine but the Installed Package scope is missing (e.g. no "Journeys Execute") or wrong MID. RCA: open the package, compare granted scopes vs the call; check account_id.
  • 400 on fire-event: wrong/typo'd EventDefinitionKey, journey not activated, or ContactKey inactive/missing. RCA: confirm journey is Running and the key matches the API entry event exactly.
  • Hardcoded subdomain: breaks after a tenant migration. Always read rest_instance_url/soap_instance_url from the token response.
  • DE upsert silently "wrong": keys{} didn't match the DE primary key β†’ it inserts dupes instead of updating. RCA: verify PK definition in Contact Builder.
  • 429 Too Many Requests: you're hammering the API β€” implement backoff/retry; batch rowsets instead of per-row calls.
  • Secret leaked / rotation: rotate Client Secret in the Installed Package immediately (critical in financial services); update the vault, not the code.
  • MCC sync lag/failure: Synchronized DE not refreshing β†’ check the integration user, sync schedule, and field-level security on the CRM object; this is a classic MOD↔SFMC INC ticket β€” start RCA at the integration user + sync logs.
  • Compliance hook (FS): never log full tokens/secrets or PII payloads in ticket notes; suppress/respect OptStatus before any send fired via API.

➑️ Next: C10_Support_Model_RCA_SLA.md

C10 β€” Support Model: INC, RCA, SLA & Troubleshooting (NEW β€” JD-critical)

🎯 Why Coforge cares: half the JD is run-the-platform β€” handle INC tickets for SFMC and MOD (CRM), do RCA, troubleshoot campaign/data/integration failures, hit SLA, coordinate critical issues. A Technical Lead is the person who calmly drives a Sev-1 send failure to closure. Theory won't save you here β€” you must say exactly how you'd triage.

🧠 One-screen mental model

  TICKET IN (INC / Sev)              THE RCA LOOP (R-I-R-F-V-P)            TICKET OUT
 β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”   β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
 β”‚ User / monitor /    β”‚    β”‚ 1 REPRODUCE   can I see it myself?     β”‚   β”‚ Fix verified β”‚
 β”‚ alert raises INC    │───▢│ 2 ISOLATE     which LAYER broke?       │──▢│ + RCA doc    β”‚
 β”‚ Assign severity     β”‚    β”‚ 3 ROOT CAUSE  the real "why" (5 whys)  β”‚   β”‚ + prevention β”‚
 β”‚ Ack within SLA      β”‚    β”‚ 4 FIX         smallest safe change     β”‚   β”‚ + comms sent β”‚
 β”‚ COMMUNICATE         β”‚    β”‚ 5 VERIFY      re-test, no regression   β”‚   β”‚ SLA met βœ…   β”‚
 β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜    β”‚ 6 PREVENT     monitor / guard / KB     β”‚   β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
        β–²                   β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
        β”‚  status updates every SLA interval (the part people forget)
        └────────────────────────────────────────────────────────────

  THE 5 LAYERS you isolate across (memorize the order = signal flow):
  DATA ──▢ CONTENT ──▢ RENDER ──▢ DELIVERABILITY ──▢ INTEGRATION (API/MCC/MOD)
  "is the row right? β†’ is the AMPscript right? β†’ does it render? β†’ did it reach? β†’ did systems talk?"
Isolate the LAYER β€” follow the signal: DATA DE / SQL / row CONTENT AMPscript / blocks RENDER HTML / preview DELIVERABILITY inbox / bounce INTEGRATION API / MCC / MOD Row right? β†’ AMPscript right? β†’ renders? β†’ reached inbox? β†’ did systems talk?
INC lifecycle (the SLA clock runs the whole time): RAISE log + severity ACK own + respond INVESTIGATE RCA loop RESOLVE fix + verify CLOSE RCA + KB ⟡ COMMUNICATE every SLA interval (Sev-1 = bridge call) ⟢ Response SLA = time to ACK · Resolution SLA = time to RESOLVE

πŸ”‘ Core in 60 seconds

  • INC vs other tickets: INCident = something broke (restore service). Compare: Service Request = "please do X" (new DE, access), Problem = the underlying root cause behind repeat INCs, Change = a planned modification. You'll live in INC + Problem + Change.
  • Severity vs Priority: Severity = business impact (who/how much is hurt). Priority = order you work (impact Γ— urgency). Sev-1 β‰  always P1, but usually is.
  • Sev ladder (FinServ flavour): Sev-1 = live send broken / wrong-data-to-clients / compliance breach / total outage. Sev-2 = major feature down, workaround exists. Sev-3 = minor / single-user. Sev-4 = cosmetic / question.
  • SLA has two clocks: Response SLA (time to acknowledge) and Resolution SLA (time to fix). Missing comms cadence breaches SLA even if you're working the fix.
  • The RCA loop = R-I-R-F-V-P: Reproduce β†’ Isolate layer β†’ Root cause β†’ Fix β†’ Verify β†’ Prevent. Skipping Prevent = the same INC comes back next week.
  • The 5 layers (signal flow): DATA β†’ CONTENT β†’ RENDER β†’ DELIVERABILITY β†’ INTEGRATION. Always isolate which layer before guessing a cause.
  • MOD (CRM) tickets: the other half β€” data not syncing CRM↔SFMC, advisor send (Distributed Marketing) failing, Marketing Cloud Connect login/sync errors. You triage across both systems and own the hand-off.
  • Agile support model: daily stand-up (queue + aging tickets + Sev-1s), shared queue/backlog, on-call rota for after-hours Sev-1, swarming on majors, sprint to burn down Problems.
  • Major Incident: a Sev-1 that needs coordination β€” you become Incident Commander: open a bridge, assign roles, drive comms, run the post-incident review (blameless RCA).

🧩 Mnemonics & memory hooks

  • RCA framework β€” "RIRFVP" β†’ say "REPAIR-VP" β†’ Reproduce, Isolate, Root-cause, Fix, Verify, Prevent. Hook: you're the VP of Repair β€” you don't just patch, you prevent.
  • The 5 layers β€” "Don't Cook Raw Dodgy Ingredients" β†’ Data, Content, Render, Deliverability, Integration. Hook: trace the signal kitchen-to-plate.
  • Severity triage β€” "WHO-WHAT-WHEN-WORKAROUND" β†’ Who is hit (1 vs all), What broke (send vs cosmetic), When (live send vs draft), Workaround? (yes β‡’ down a notch). Hook: 4 W's set the Sev.
  • Ticket types β€” "I-S-P-C" β†’ Incident, Service request, Problem, Change. Hook: "I Solve Problems & Changes."
  • Sev-1 first moves β€” "ACT-C" β†’ Assess scope, Contain (pause/stop the bleed), Tell stakeholders, Commander assigned. Hook: in a crisis, you ACT-Calmly.
  • Comms cadence β€” "Heartbeat rule" β†’ a Sev-1 with no update is a dead patient; send a heartbeat every interval even if it's "still investigating." Hook: silence breaches SLA.
  • 5 Whys β€” "Ask why till it stops being a person's fault" β†’ keep asking why until the answer is a system/process gap, not "Bob forgot." Hook: blame the process, not Bob.

πŸ’€ Skeletons to memorize

RCA write-up template (the artifact that closes a Sev-1):

INC-#####  | Sev: 1  | System: SFMC (+ MOD)  | Owner: A.Panda
SUMMARY      : Mortgage-rate journey sent blank %%FirstName%% to 12,430 clients.
IMPACT       : 12,430 advisor-branded emails, FinServ brand risk, 3 complaints.
TIMELINE     : 09:02 send β†’ 09:08 alert β†’ 09:11 ack β†’ 09:19 paused β†’ 09:46 fixed.
ROOT CAUSE   : SQL import to sendable DE ran AFTER the schedule fired (race) β†’
               FirstName column null for new rows. (5-Whys: schedule order not enforced.)
RESOLUTION   : Re-sequenced automation (import β†’ wait β†’ send); resent w/ AMPscript default.
DETECTION    : Catch-block email alert on automation error fired in 6 min.
PREVENTION   : (1) AMPscript IIF default on FirstName  (2) verification step + row-count gate
               (3) monitoring alert on null-key %  (4) KB article linked.
SLA          : Response 9m (≀15 βœ…)  Resolution 44m (≀4h βœ…).

πŸ” Line by line: - INC-#### / Sev / System / Owner β€” the header an interviewer wants first: what, how bad, where, who drove it. - SUMMARY β€” one plain sentence a manager can read; lead with the user-visible symptom. - IMPACT β€” quantify (count + business/compliance angle) β€” in FinServ "brand risk / complaints" is the language that matters. - TIMELINE β€” timestamps prove SLA + show fast detectionβ†’containment; this is your credibility. - ROOT CAUSE β€” the real why via 5-Whys, ending at a process gap (schedule order), not a person. - RESOLUTION β€” the smallest safe fix that restored service (re-sequence + resend). - DETECTION β€” how you knew β€” proves monitoring exists (or exposes the gap to fix). - PREVENTION β€” multiple guards so it can't recur: code default + verification + monitoring + KB. - SLA β€” explicit response & resolution numbers vs target β€” this is what "SLA adherence" looks like on paper.

AMPscript defensive default (kills the #1 personalization INC):

%%[ VAR @fname SET @fname = AttributeValue("FirstName")
    IF EMPTY(@fname) THEN SET @fname = "Valued Client" ENDIF ]%%
Dear %%=v(@fname)=%%,

πŸ” Line by line: - VAR @fname / AttributeValue("FirstName") β€” pull the field into a variable so you can test it before printing. - IF EMPTY(@fname) ... "Valued Client" β€” the guard: never let a blank/null field render an empty greeting to a client. - %%=v(@fname)=%% β€” print the safe value; a missing-data row degrades gracefully instead of becoming a Sev-1.

Automation error alert (so a failure pages YOU, not the client):

SSJS Script Activity (last step) OR automation "Error" notification:
  try { ...verification query / row count... }
  catch(e) {
     /* send alert email to support DL with automation name + error */
  }
Automation Studio β–Έ automation β–Έ Settings β–Έ "Notify on Error" β†’ support@bank.com

πŸ” Line by line: - try { verification } β€” run a sanity check (e.g., row count > 0, null-key % = 0) as a guarded step. - catch(e) { send alert } β€” on failure, you get emailed with the automation name + error text β€” detection in minutes. - Notify on Error β€” the no-code safety net: the built-in automation notification mails the support DL on any step failure.

πŸ› οΈ In practice (what you would actually click / do)

πŸ”΄ Triage a Sev-1 "campaign failed to send" under SLA β€” the exact runbook: 1. Acknowledge first (stop the clock): reply on the INC "Owned by A.Panda, investigating, next update in 15 min." Comms before cleverness. 2. Contain the bleed: Journey Builder β–Έ open journey β–Έ Pause (choose all running versions; decide whether to extend Wait durations) β€” or Automation Studio β–Έ Pause/Stop the running automation. For a User-Initiated send: Email Studio β–Έ Sent β–Έ stop further sends. Don't fix yet β€” stop more bad emails first. 3. Find the failure: Automation Studio β–Έ the automation β–Έ Activities / Run History β†’ red step + error text. For journeys: Journey Builder β–Έ History / Journey Analytics β†’ activity with high error/skip; search a single Subscriber Key in Contact History to see the exact failing step + message. 4. Isolate the layer (D-C-R-D-I): Did the import fail (Automation Studio error) = DATA? Did AMPscript throw = CONTENT? Renders but wrong = RENDER? Sent but bouncing = DELIVERABILITY? Marketing Cloud Connect / API / MOD sync error = INTEGRATION? 5. Confirm with data: Email Studio β–Έ Subscribers or Data Extension β–Έ Records β†’ query the sendable DE; Tracking β†’ Sends/Bounces/Errors; Setup β–Έ Sender Authentication / SAP for deliverability. 6. Fix smallest-safe: re-sequence the automation, add AMPscript default, fix the SQL filter, re-validate the DE. Resend only the affected segment (build a DE of impacted SubscriberKeys, send to that). 7. Verify: send to a seed/test DE first; Preview & Test β–Έ Preview with a real subscriber; row-count gate = 0 nulls; then release. 8. Close + RCA: fill the RCA template, link the KB article, add a monitoring alert so it self-detects next time.

Where the buttons live (memorize the click-paths): - Pause a journey: Journey Builder β–Έ open journey β–Έ ... menu / Pause β–Έ choose current vs all versions β–Έ optionally extend Wait-by-Duration. - Automation run history / errors: Automation Studio β–Έ Overview β–Έ open automation β–Έ Activities tab / Run History β–Έ click the red step. - Per-contact journey path: Journey Builder β–Έ journey β–Έ Contacts / History β–Έ search SubscriberKey β–Έ read step statuses. - Send / bounce / error tracking: Email Studio β–Έ Tracking β–Έ (Overview / Bounces / Not Sent). - Deliverability / auth: Setup β–Έ Sender Authentication Package, and Email Studio β–Έ Admin β–Έ Reputation (or 250ok/Validity if licensed). - MCC / MOD sync errors: Setup β–Έ Marketing Cloud Connect β–Έ check API user + connection; in CRM check the Distributed Marketing managed package logs / Entry DE writes.

Set up so failures page you (prevention, the Tech-Lead move): - Automation Studio β–Έ automation β–Έ Settings β–Έ Notify on Error/Skip/Complete β†’ support DL. - Add a verification Script/Query step (row count, null %, dup check) as the last step before send; fail loud. - Journey Builder β–Έ Validate before activate; Email β–Έ Preview & Test with seed subscribers every deploy. - Keep a runbook + KB per recurring INC; review aging tickets at daily stand-up.

🎀 Rapid-fire

  • Q: Difference between an Incident and a Problem? β†’ INC = restore service now; Problem = find/fix the root cause so INCs stop recurring. …and in practice: I open a Problem record when the same INC appears 3Γ— β€” e.g. repeated null-personalization β€” and fix the process in a Change.
  • Q: Severity vs Priority? β†’ Severity = business impact; Priority = work order (impact Γ— urgency). …and in practice: a cosmetic typo on a live FinServ disclosure email is low severity, high priority because compliance is urgent.
  • Q: What's your RCA framework? β†’ Reproduce β†’ Isolate layer β†’ Root cause (5-Whys) β†’ Fix β†’ Verify β†’ Prevent. …and in practice: I always isolate across DATAβ†’CONTENTβ†’RENDERβ†’DELIVERABILITYβ†’INTEGRATION before touching anything.
  • Q: First 3 things on a Sev-1 send failure? β†’ Acknowledge/comms, contain (pause journey/automation), assess scope. …and in practice: I pause the journey for all running versions in Journey Builder before I even start diagnosing.
  • Q: Personalization came out blank β€” why? β†’ null/missing field, wrong attribute name, AttributeValue vs Lookup, or send fired before import. …and in practice: I check the sendable DE row, add an IIF/IF EMPTY default, and re-sequence import-before-send.
  • Q: How do you find which contacts failed and where? β†’ Journey Analytics for the failing activity, then search the SubscriberKey in Contact History. …and in practice: that pinpoints the exact step + error message per contact.
  • Q: A MOD/CRM ticket says advisor emails aren't sending β€” where do you look? β†’ Marketing Cloud Connect API user, the Distributed Marketing Entry DE writes, and the Journey behind the DM send. …and in practice: I confirm sendFromEmail is a verified sender and the journey is available to DM.
  • Q: How do you prove you met SLA? β†’ Timeline timestamps: ack time vs response SLA, resolved time vs resolution SLA, plus the comms log. …and in practice: I put the SLA line in the RCA doc with both numbers vs target.
  • Q: What makes a good prevention step? β†’ Layered: code guard + verification step + monitoring alert + KB. …and in practice: one fix isn't enough β€” I add a null-% monitor and an AMPscript default so it can't silently recur.
  • Q: What's a blameless post-incident review? β†’ Focus on system/process gaps, not the person; 5-Whys ends at a process fix. …and in practice: "schedule order wasn't enforced," never "Bob ran it early."

⚠️ Gotchas / RCA hooks

  • Race condition: send fires before import finishes β†’ blank personalization to live clients. RCA hook: re-sequence automation import β†’ wait/verify β†’ send; add row-count gate; AMPscript default as last line of defense.
  • Pausing a journey silently extends Wait activities β†’ contacts resume late or "stuck." RCA hook: on resume, check/extend Wait-by-Duration deliberately; avoid Waits < 15 min; final-step Waits can drop to ~1 min.
  • "Contacts stuck in journey" β†’ often a Wait still in progress, an unmet Decision Split, or a failed activity. RCA hook: search SubscriberKey in Contact History; if the final Wait hasn't completed it's just "in progress," not stuck.
  • Deliverability dropped overnight β†’ IP/domain reputation, SPF/DKIM/DMARC broke, spam-trap hit, or no suppression. RCA hook: check SAP/authentication, bounce category, recent list source; FinServ = enforce suppression + consent before resend.
  • Data "not updating / segmentation wrong" β†’ SQL query targeting stale DE, filter logic, or MCC sync lag CRM↔SFMC. RCA hook: run the query manually, check the automation that populates the DE, verify the MCC sync ran; never trust a segment you didn't row-count.
  • API/integration failure (REST/SOAP/MCC/MOD) β†’ expired token, throttling/429, package permissions, or API user locked. RCA hook: check the API user, re-auth, inspect response code; 401=auth, 429=rate-limit, 500=SFMC side.
  • SLA breached while you were "busy fixing" β†’ you owe comms, not just a fix. RCA hook: set a recurring heartbeat update; the clock counts silence as a breach.
  • Closing the INC without Prevent β†’ it returns next cycle as a repeat. RCA hook: never close a Sev-1 without a monitoring alert + KB entry + (if recurring) a Problem record.
  • Fixing on production with no test β†’ you turn one INC into two. RCA hook: always seed-send to a test DE and Preview a real subscriber before the corrected resend.

➑️ Next: C11_Deliverability_and_Compliance.md

C11 β€” Deliverability & Compliance

🎯 Why Coforge cares: advisor/financial-services emails are useless if they land in spam or break consent law β€” the JD wants someone who runs journeys, validates deployments, and resolves "campaign/data/integration failures" with proper RCA. Auth + consent IS the failure surface.

🧠 One-screen mental model

            YOUR SEND (SFMC)                    RECEIVER (Gmail/Yahoo) checks
            ----------------                    ----------------------------
  From: advisor@news.bankco.com
        |                                        1) SPF  -> "Is this IP allowed
        |  envelope (Return-Path/MAIL FROM)   ----->  to send for this domain?"
        |     bounce.sfmc-domain.com                   (checks Return-Path domain)
        |
        |  DKIM signature (header)            ----->  2) DKIM -> "Is the signature
        |     d=news.bankco.com                        valid? content untampered?"
        |
        v                                              3) DMARC -> "Does SPF or DKIM
  Header From: news.bankco.com                          domain ALIGN with header From?
                                                         If fail -> p=none/quarantine/reject"
  ALIGNMENT = the domains must MATCH the visible From
  ---------------------------------------------------------------------------
  Pass all 3 + good reputation (low spam rate, clean list)  => INBOX
  Auth ok but bad reputation/content/traps                  => SPAM folder
  Auth fail / blocklisted IP                                => BOUNCE / reject

πŸ”‘ Core in 60 seconds

  • SPF = which IPs may send for the domain (checks the envelope Return-Path). DNS TXT record.
  • DKIM = cryptographic signature proving the mail wasn't tampered + came from the domain. Public key in DNS.
  • DMARC = the policy that ties SPF/DKIM to the visible From via alignment, and tells receivers what to do on fail (p=none monitor β†’ p=quarantine β†’ p=reject). Also enables reporting.
  • Alignment is the whole game: SPF/DKIM can pass for some random domain and DMARC still fails β€” the authenticated domain must match the From: domain the user sees.
  • SAP (Sender Authentication Package) = the SFMC add-on that gives you a branded sending domain + dedicated IP + branded CloudPages/links/reply and lets you set SPF/DKIM/DMARC properly. FinServ should always be on SAP.
  • Dedicated IP must be warmed = ramp volume slowly so the IP builds reputation (don't blast 1M on day 1).
  • Hard bounce = permanent (bad address/domain) β†’ suppress immediately. Soft bounce = temporary (mailbox full, server down) β†’ retry, suppress after repeated fails.
  • Gmail/Yahoo 2024 rules (bulk = 5,000+/day to Gmail): SPF + DKIM + DMARC (min p=none), spam rate < 0.3% (aim < 0.1%), one-click List-Unsubscribe, honor opt-outs in 2 days. Enforced Feb–Apr 2024.
  • Laws: CAN-SPAM (US, opt-OUT), GDPR (EU, opt-IN + rights), DPDP (India, consent-first, 22-language notices, Consent Managers, under-18 = child).

🧩 Mnemonics & memory hooks

  • SPF / DKIM / DMARC = "Sender Permitted From / Don't Key-tamper / Decide Mismatch Action, Report Compliance."
  • SPF = who's allowed (the guest list). DKIM = tamper seal (wax seal on the envelope). DMARC = the bouncer who checks the seal AND the name on the door (alignment) and decides reject/quarantine.
  • Alignment = "Does the seal match the storefront sign?" SPF/DKIM can be valid for a back-alley domain; DMARC only passes if it matches the From the customer reads.
  • Warming = "Idle the engine before flooring it." Cold IP + big blast = engine seize (blocklist).
  • Gmail/Yahoo 2024 = "A.S.U. β†’ All Senders Unsubscribe": Auth (SPF+DKIM+DMARC), Spam-rate < 0.3%, Unsubscribe one-click in 2 days.
  • Laws = "US Opts-OUT, EU Opts-IN, India CONSENTS." CAN-SPAM=out, GDPR=in, DPDP=consent-first.
  • FinServ compliance = "CASS": Consent (proof), Archival (retain sends), Suppression (honor & hold), Sensitive data (never PII like account/SSN in the email body).
  • Bounce = "Hard = History (gone forever, suppress now). Soft = Snooze (retry, then suppress)."

πŸ’€ Skeletons to memorize

DNS records the auth standards live in (this is what you verify, not write in SFMC):

SPF   (TXT @)              v=spf1 include:cust-spf.exacttarget.com -all
DKIM  (TXT s1._domainkey)  v=DKIM1; k=rsa; p=MIGfMA0...<public key>...
DMARC (TXT _dmarc)         v=DMARC1; p=quarantine; rua=mailto:dmarc@bankco.com; pct=100; aspf=s; adkim=s

πŸ” Line by line: - v=spf1 include:... -all β€” declares SPF; include trusts SFMC's sending hosts; -all = hard-fail anything else (use ~all softfail while testing). - s1._domainkey ... p=MIG... β€” the DKIM public key under a selector (s1); receivers fetch it to verify the signature SFMC adds with the private key. - _dmarc ... p=quarantine β€” DMARC policy: p = action on fail (none/quarantine/reject), rua = where aggregate reports go, pct = % of mail the policy applies to, aspf=s/adkim=s = strict alignment (domains must match exactly, not just the org domain).

One-click unsubscribe headers the receiver looks for (SFMC adds these on commercial sends with SAP/correct config):

List-Unsubscribe: <https://click.bankco.com/unsub?id=%%subscriberid%%>, <mailto:unsub@bankco.com>
List-Unsubscribe-Post: List-Unsubscribe=One-Click

πŸ” Line by line: - List-Unsubscribe: β€” gives a URL and a mailto so clients show a native "Unsubscribe" button; the URL carries the subscriber id so you can resolve who opted out. - List-Unsubscribe-Post: ...One-Click β€” the 2024-required line that lets Gmail/Yahoo POST the opt-out without the user visiting a landing page; you must process it within 2 days.

AMPscript guard so sensitive accounts/PII never render in a FinServ email:

%%[
  SET @acct = AttributeValue("AccountNumber")
  SET @masked = Concat("****", Substring(@acct, Subtract(Length(@acct),4), 4))
]%%
Your account ending %%=v(@masked)=%% has a new statement.

πŸ” Line by line: - SET @acct = AttributeValue(...) β€” pulls the raw account number from the sendable DE. - Concat("****", Substring(...)) β€” keeps only the last 4 digits, masking the rest β€” never email a full account/SSN. - %%=v(@masked)=%% β€” outputs the masked value; the full number stays in the DE, out of the email body and any forwarded copy.

πŸ› οΈ In practice (what you would actually click / do)

Set up / verify authentication (SAP): - Setup β†’ (gear) β†’ Company Settings / Sender Authentication Package to confirm SAP is provisioned (branded domain, dedicated IP, branded links/CloudPages). - Email Studio β†’ Admin β†’ Send Management β†’ Sender Profiles β€” confirm the From name/address uses the authenticated domain (e.g. news.bankco.com), not the default *.exacttarget.com. - Verify DNS externally: run the domain through MXToolbox (spf:, dkim:, dmarc: lookups) or dmarcian, and send a test to mail-tester.com for a 10/10 auth score before any FinServ campaign.

Diagnose "delivered but landing in spam" (the practical RCA they'll ask): 1. Send a seed/test to your own Gmail + Yahoo + Outlook (Email Studio β†’ Preview & Test β†’ send test, or a seed list). Open the message β†’ Show original in Gmail to read SPF=PASS DKIM=PASS DMARC=PASS. Any FAIL β†’ auth/alignment problem. 2. Google Postmaster Tools (postmaster.google.com, domain pre-verified via DNS): check Spam Rate (must be < 0.1%, hard line 0.3%), Domain/IP Reputation (want High/Medium), Authentication dashboard, and Feedback Loop. Yahoo β†’ Sender Hub / CFL. 3. Check the IP/domain against blocklists (MXToolbox blacklist check, Spamhaus, SNDS for the IP). 4. Reputation/content fixes: if auth passes but reputation is poor β†’ it's a list/content problem. In SFMC pull Tracking for the send (Email Studio β†’ Tracking, or Reports) β€” high complaints/low engagement β†’ tighten segmentation, run sunset suppression, check spammy subject/links and image-to-text ratio, ensure visible unsubscribe. 5. Confirm one-click unsub is present: view headers for List-Unsubscribe + List-Unsubscribe-Post. Missing β†’ fix Sender Profile / commercial vs transactional classification.

Bounce handling & list hygiene: - Email Studio β†’ Tracking β†’ Bounces, or build an Automation that queries _Bounce data view by BounceCategory (Hard / Soft / Block). - Hard bounces β†’ add to a suppression DE / All Subscribers status = Held; SFMC auto-holds after repeated hard bounces. - Sunset policy = an Automation/SQL job that suppresses addresses with no opens/clicks in N days (e.g. 180) β†’ query _Open/_Click data views, write non-engagers to a suppression DE, exclude it on every send (Send Definition β†’ Exclusion).

Consent / suppression for FinServ: - Maintain a global suppression list (Email Studio β†’ Subscribers β†’ Suppression Lists or a master DE referenced as Exclusion) for opt-outs, complaints, and DNC. - Capture consent timestamp/source in the DE; for Distributed Marketing, advisors send from approved templates so consent + branding stay centrally controlled.

🎀 Rapid-fire

  • Q: What does SPF actually check? A: The envelope/Return-Path domain against the sending IP β€” not the visible From. …and in practice: in Gmail "Show original," SPF shows the mailfrom/Return-Path domain, which under SAP is your branded bounce domain.
  • Q: SPF and DKIM pass but mail still fails DMARC β€” why? A: Alignment β€” the authenticated domain doesn't match the visible From domain. …and in practice: fix the Sender Profile to send from the SAP-branded domain so DKIM d= aligns with From.
  • Q: Difference between p=none, quarantine, reject? A: none = monitor only (still inbox), quarantine = spam folder, reject = blocked outright. …and in practice: start p=none, read rua reports for weeks, then tighten.
  • Q: Hard vs soft bounce action? A: Hard = suppress immediately (permanent); soft = retry, suppress after repeated fails. …and in practice: query _Bounce data view by BounceCategory in an Automation and write Hard to the suppression DE.
  • Q: Gmail/Yahoo 2024 must-haves? A: SPF+DKIM+DMARC, spam rate < 0.3%, one-click unsubscribe honored in 2 days; bulk = 5,000+/day to Gmail. …and in practice: verify spam rate in Postmaster Tools and the List-Unsubscribe-Post header in a seed test.
  • Q: What's an IP warm-up? A: Gradually ramping volume on a new dedicated IP so it earns reputation. …and in practice: send to your most-engaged segments first, increase daily volume on a schedule.
  • Q: CAN-SPAM vs GDPR vs DPDP in one line each? A: US opt-OUT + honor unsub; EU opt-IN + data rights; India consent-first, multi-language notice, Consent Managers.
  • Q: What's a spam trap? A: An address that only exists to catch senders with poor hygiene (pristine traps never opted in; recycled traps are abandoned addresses). …and in practice: a sunset policy removing long-term non-engagers is your main defense.
  • Q: How do you prove a FinServ email is compliant? A: CASS β€” Consent record, Archival of the send, Suppression honored, Sensitive data masked.

⚠️ Gotchas / RCA hooks

  • "It went to spam but auth passes" β†’ it's reputation/content/list, not auth. RCA: Postmaster spam-rate + reputation, then segmentation/sunset, not DNS.
  • Alignment trap: copying SPF/DKIM but still sending from the default *.exacttarget.com From β†’ DMARC fails. Always send from the SAP branded domain.
  • Cold dedicated IP blasted at full volume β†’ instant blocklist + spam folder. Warm it; ramp by engagement tier.
  • Soft bounces ignored β†’ repeated retries to dead mailboxes quietly tank reputation. Automate suppression after N soft fails.
  • Missing/late unsubscribe β†’ opt-outs not honored within 2 days = Gmail/Yahoo penalty + legal exposure. RCA: check List-Unsubscribe-Post header + that the suppression job runs on schedule.
  • Sensitive data leak: full account number/SSN in the body β†’ compliance incident even if delivered. Mask with AMPscript; never email PII.
  • Spam traps from old purchased lists β†’ never buy lists; FinServ must use consented, sunset-maintained lists only.
  • DMARC p=reject set too early β†’ legit mail rejected; treat as a P1 incident. RCA: read rua reports first, fix alignment, then escalate the policy gradually.

➑️ Next: C12_FinServ_and_Lead_Behaviors.md

C12 β€” Financial-Services Domain & Technical-Lead Behaviors

🎯 Why Coforge cares: this is a Technical-Lead seat in Financial Services β€” they need someone who runs advisor/client campaigns under compliance, consent & suppression, leads RCA & major incidents to SLA, and makes solution/trade-off calls for a team β€” not just an AMPscript coder.

🧠 One-screen mental model

        FINANCIAL-SERVICES SFMC  (advisor β†’ client, regulated)
        ─────────────────────────────────────────────────────

   CENTRAL MARKETING (you/lead)            DISTRIBUTED MARKETING
   builds compliant templates  ───────►    advisor sends from
   + locked content + approvals            CRM (Quick Send)
                                                  β”‚
                                                  β–Ό
   DATA ─► [Consent/Preference] ─► [Suppression] ─► SEND ─► Client
   (PII)      opt-in/opt-down       global block      β”‚
     β”‚             β”‚                     β”‚            β–Ό
     β–Ό             β–Ό                     β–Ό        [Tracking +
  encrypt /    Publication Lists    Suppression    ARCHIVE/AUDIT]
  field-level  + Profile Center     List + Excl.   (who got what,
  security     (subscriber choice)  Script (logic)  when, version)

   β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ LEAD WRAPS THE WHOLE THING ────────────────┐
   β”‚ Designβ–ΈEstimateβ–ΈReviewβ–ΈMentorβ–ΈCommunicateβ–ΈRCAβ–ΈPlan-for-Peak β”‚
   β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

πŸ”‘ Core in 60 seconds

  • FS = consent is king. No send without provable opt-in. Every comm must be suppressible, auditable, archivable.
  • Advisor model = Distributed Marketing (DM). Central team owns compliant, locked templates; advisors personalize + send from Sales/Service Cloud via Quick Send / campaigns; approval workflow can gate the send.
  • Two layers of "don't send": Preference (subscriber's choice β†’ Publication Lists / Profile Center) vs Suppression (your internal hard block β†’ Suppression List + Exclusion Script). Both filter; suppression always wins.
  • PII handling: minimize PII in DEs, use Field-Level Encryption (and Tokenized Sending for SMS/MobileConnect, where a token replaces PII in the message), keep Einstein off regulated data, restrict via Roles/Business Units, never log PII in scripts/error tables.
  • Audit/archival: keep send logs, template versions, approval trail, consent timestamps β€” FS regulators (FINRA/SEC-style) expect "prove who approved & who received what."
  • Lead β‰  doer. You own solution design, estimates, code standards, mentoring, stakeholder comms, RCA leadership, peak/capacity planning, Agile ceremonies.
  • SLA mindset: P1/P2 incidents on SFMC and MOD (CRM) β†’ triage β†’ mitigate β†’ RCA β†’ preventive action.

🧩 Mnemonics & memory hooks

  • FS data rules = "CASPA" β†’ Consent, Archive, Suppress, PII-protect, Approve. "In finance, you CASPA before you cast."
  • Lead behaviors = "DERM-SCAP" β†’ Design, Estimate, Review (code), Mentor β€” Stakeholder-comm, Capacity/peak, Agile, Postmortem(RCA). "A good lead has thick DERM and a SCAP-el for incidents."
  • Don't-send layers = "PuSE" β†’ Publication list (preference) β†’ Suppression list β†’ Exclusion script. "PuSE the brakes before every send." (left-to-right = subscriber choice β†’ hard block β†’ runtime logic)
  • Incident order = "DRIP" β†’ Detect, Restore (mitigate first), Investigate (RCA), Prevent. "Stop the DRIP before you find the leak."
  • Approval flow = "SEAL" β†’ Submit, Edit-lock, Approve, Launch. "In FS, every send carries a SEAL."

πŸ’€ Skeletons to memorize

1. Exclusion Script (runtime "don't send" with logic β€” the FS suppression workhorse)

%%[
  /* runs per-subscriber at send time; true = EXCLUDE this person */
  VAR @consent, @hardBounce
  SET @consent   = AttributeValue("EmailConsent")
  SET @hardBounce = AttributeValue("HardBounceFlag")

  IF @consent != "Y" OR @hardBounce == "true" THEN
     RaiseError("Excluded: no consent / bounced", false)
  ENDIF
]%%

πŸ” Line by line: - VAR/SET @consent β€” pull the subscriber's consent flag from the sendable DE/profile at send time. - @hardBounce β€” pull a deliverability flag so you never re-mail a dead address (FS reputation matters). - IF ... RaiseError(msg, false) β€” if not opted-in or bounced, raise error; the false means "skip just this subscriber," not the whole send. - Net effect: only provably-consented, deliverable contacts get the email β€” defensible in an audit.

2. AMPscript regulated-disclosure + advisor personalization block

%%[
  VAR @advName, @advNMLS, @client
  SET @advName  = AttributeValue("AdvisorName")
  SET @advNMLS  = AttributeValue("AdvisorLicenseID")
  SET @client   = AttributeValue("FirstName")
]%%
Dear %%=v(@client)=%%, your advisor %%=v(@advName)=%% (Lic# %%=v(@advNMLS)=%%)...
<!-- Required FS disclosure stays hard-coded, NOT advisor-editable -->

πŸ” Line by line: - Pull advisor identity + license/NMLS ID β€” regulated comms must name the licensed sender. - Greet the client by first name only (minimize PII in body). - The disclosure line is template-locked so an advisor in Distributed Marketing can't strip mandatory legal text.

3. SQL: build a daily suppression DE (consent + cooling-off + DNC)

SELECT s.SubscriberKey, s.EmailAddress
FROM   Master_Contacts s
WHERE  s.EmailConsent <> 'Y'
   OR  s.DoNotContact  =  'Y'
   OR  s.LastContactDate > DATEADD(day, -7, GETDATE())  -- frequency cap

πŸ” Line by line: - Pull anyone not opted-in β†’ must be suppressed. - DoNotContact = 'Y' β†’ honors DNC / regulator request. - LastContactDate > -7 days β†’ enforces a frequency cap / cooling-off so clients aren't over-mailed. - Output DE is attached as a Suppression List on the send β†’ centrally enforced, audit-friendly.

πŸ› οΈ In practice (what you would actually click / do)

Set up advisor sends (Distributed Marketing): - In Marketing Cloud Setup β–Έ Distributed Marketing, install the managed package into Sales/Service Cloud; map the sending BU and DM-enabled DEs. - Build the email in Content Builder, then in DM mark regions as locked vs editable so advisors edit only approved zones. - Advisor side: opens a Contact/Lead/Campaign record β–Έ Quick Send (single) or a DM Campaign (bulk/segment) β–Έ personalizes editable fields β–Έ Preview (bulk preview shows first 100) β–Έ Submit for approval β–Έ Send/Schedule. - Turn on manual approval in DM so a compliance reviewer must approve before launch.

Enforce consent & suppression on a normal Email Studio send: - Email Studio β–Έ Subscribers β–Έ Suppression Lists β–Έ create list / import the daily suppression DE. - In Guided Send β–Έ Step "Who", attach the Suppression List; in Step "Options/Delivery" paste an Exclusion Script for runtime logic. - Subscriber preferences: Email Studio β–Έ Subscribers β–Έ Publication Lists + a CloudPage Profile/Subscription Center so clients self-manage opt-downs.

Protect PII / lock down access: - Setup β–Έ Users β–Έ Roles β€” least-privilege; advisors get send-only, not data export. - Setup β–Έ Business Units β€” segregate regulated data; sensitive DEs live in a restricted BU. - Use Field-Level Encryption for PII at rest (and Tokenized Sending for SMS/MobileConnect, where a token stands in for PII); never write PII into _Bounces/error DEs or RaiseError text.

Audit & archival (the FS differentiator): - Keep Tracking + Data Views (_Sent, _Open, _Click, _Bounce) exported nightly via Automation Studio to an archive DE / SFTP. - Version templates in Content Builder (or external repo) and retain the DM approval trail β€” answer "who approved, who received, which version, when."

Lead-the-work moves (say these out loud in interview): - "I'd run a discovery β†’ solution-design doc β†’ effort estimate (T-shirt/story points) before the team codes." - "I enforce code review against a standards checklist (AMPscript guard-rails, no PII in logs, naming, error handling)." - "For peak (e.g., statement season / rate-change blast), I do capacity planning: pre-warm sends, stagger throttling, lock change-freeze windows." - "In Agile ceremonies I groom the backlog, size stories, run stand-ups, and own the demo + retro actions."

Reframed GAP STAR stories (FS / Tech-Lead lens):

Your GAP story FS Tech-Lead reframe
DE Lookup WSProxy tool "Built reusable SSJS/WSProxy data-lookup so the team validated client/advisor data accuracy fast β€” I designed it as shared tooling and mentored juniors to use it."
Dynamic barcodes / countdowns (MovableInk) "Real-time personalization, but in FS I'd gate it β€” no live-personalized regulated figures without approval; show design trade-off awareness."
A/B testing framework "Led a standardized A/B + validation framework = my code-standards/quality contribution; in FS, A/B only on non-regulated copy, never on disclosures."
VAWP / Peak escalation "Led the major-incident bridge: detected, mitigated send failure, ran RCA, drove preventive action + capacity plan for next peak β€” exactly the SLA/RCA lead behavior."

3 questions to ask the interviewer: 1. "How is Distributed Marketing / advisor sending set up today β€” central templates with locked content, and where does compliance approval sit in the flow?" 2. "What does the incident model look like for SFMC + MOD β€” SLA tiers, who leads RCA, and how mature is the preventive-action loop?" 3. "What are the biggest data-accuracy / consent pain points the team hits during peak (statements, rate changes), and how do you currently plan capacity?"

🎀 Rapid-fire

  • Q: Preference vs suppression? A: Preference = subscriber's choice (Publication List/Profile Center); suppression = your hard block. Suppression always wins. …and in practice: attach a Suppression List in Guided Send "Who," manage preferences via a CloudPage subscription center.
  • Q: How do advisors send compliant emails themselves? A: Distributed Marketing β€” central locked templates, advisor personalizes editable zones, optional manual approval, then Quick Send/campaign. …and in practice: record β–Έ Quick Send β–Έ edit β–Έ preview β–Έ submit for approval β–Έ send.
  • Q: Suppression list vs exclusion script β€” when each? A: List = static/known keys (DNC, bounces). Script = runtime logic on profile attributes. …and in practice: combine β€” daily SQL builds the list, exclusion script catches edge logic at send time.
  • Q: How do you keep PII safe? A: Least-privilege Roles, restricted BUs, field-level encryption (Tokenized Sending for SMS), no PII in logs/error text.
  • Q: What's your incident order? A: DRIP β€” Detect, Restore (mitigate), Investigate (RCA), Prevent. Mitigate before you diagnose.
  • Q: As a lead, how do you estimate? A: Discovery β†’ break into stories β†’ T-shirt/story-point sizing with buffer for testing/validation; surface risks early.
  • Q: How do you run code review on AMPscript? A: Standards checklist β€” error handling, no PII in logs, RaiseError(...,false) for per-sub skip, naming, idempotent automations, peak-safe throttling.
  • Q: How do you prove a regulated send was compliant? A: Consent timestamp + suppression applied + approval trail + template version + Data View send logs archived to SFTP.

⚠️ Gotchas / RCA hooks

  • RaiseError without false kills the whole send, not one subscriber β†’ in FS that's a missed regulated comm. RCA: check the exclusion/error script's second arg; always false for per-subscriber skip.
  • Suppression not applied / wrong DE attached β†’ opted-out client gets mailed = compliance breach. RCA: verify the Suppression List on the send job + that the nightly SQL automation actually ran (Automation Studio activity log).
  • PII leaked into _Bounces or RaiseError text β†’ audit finding. RCA: scrub scripts; log SubscriberKey only, never email/SSN/account numbers.
  • Advisor edited locked content (DM mis-configured) β†’ unapproved legal text goes out. RCA: confirm locked regions + manual-approval toggle in DM setup.
  • Frequency cap missed during peak β†’ over-mailing, spam complaints, sender-reputation drop. RCA: check cooling-off SQL window + send throttling; add to capacity plan.
  • Approval bypassed (scheduled send skipped review) β†’ note: scheduling is allowed only when manual approval isn't required; if compliance needs review, don't enable schedule-without-approval. RCA: audit DM approval settings.
  • MOD (CRM) ↔ SFMC sync lag β†’ stale consent flag, you mail someone who just opted out. RCA: check integration/sync job timing; suppress on the freshest source of truth, add reconciliation step.

➑️ Next: C13_Memory_Vault.md

C13 β€” Memory Vault (everything to recall, in one place)

🎯 Why Coforge cares: this is your pre-interview cram sheet β€” one screen that reloads the whole SFMC stack (campaigns, journeys, DEs, SQL, AMPscript, APIs, deliverability, RCA, SLAs) so you answer fast and hands-on, not theory-only.

🧠 One-screen mental model

   THE WHOLE COURSE ON ONE PAGE
   ─────────────────────────────────────────────────────────────────
   PEOPLE        Contact (Contact Key) ── same key ──▢ Subscriber (Subscriber Key)
                 All Contacts  βŠ‡  All Subscribers
                       β”‚
   DATA          Data Extensions (6 types) ── SQL / imports ──▢ Automation Studio
                       β”‚  (sendable + linked to _SubscriberKey)
                       β–Ό
   PERSONALIZE   AMPscript / Dynamic Content  ── Lookup() into other DEs ──▢ rendered email
                       β”‚
   SEND          Email Studio  ── Send Classification (sender+delivery) ──▢ ISP
                 Journey Builder ── Entry β†’ Wait/Decision β†’ Activities ──▢ Goal
                 Distributed Mktg ── advisor picks journey β†’ personalize β†’ approve β†’ send
                       β”‚
   PROTECT       SAP: SPF + DKIM (Salesforce sets) ; DMARC (you add)  ──▢ inbox not spam
                       β”‚
   MEASURE       Data Views (_Sent _Open _Click _Bounce _Sub _Job) β†’ Analytics / SQL
                       β”‚
   INTEGRATE     REST/SOAP APIs ── OAuth2 v2/token (~20 min) ──▢ MOD/CRM
                       β”‚
   SUPPORT       INC ticket β†’ Triage β†’ RCA loop β†’ Fix β†’ SLA met β†’ Postmortem
   ─────────────────────────────────────────────────────────────────
CONTACT MODEL β€” same key, two hats Contact 1 per human Β· Contact Key Subscriber email channel Β· Subscriber Key SAME string All Contacts (Contact Builder) βŠ‡ All Subscribers (Email Studio) Never put the email address in the key (FinServ PII + churn) β€” use the MOD/CRM id
SEND FLOW DE (audience) Personalize Send (classif.) ISP / inbox Tracking
JOURNEY CANVAS Entry (DE/API) Wait Decision split Email activity Goal / Exit
OAuth 2.0 FLOW (REST) Your app + clientId/secret POST …auth…/v2/token returns access_token (~20 min) …rest…/data/v1/… call Bearer token in Authorization header
RCA LOOP β€” "REPAIR-VP" (RIRFVP) Reproduce Isolate Root cause Fix Verify + prevent Prevent β€” learnings feed back into monitoring & QA
DE TYPES β€” "Stan Filled Random Shared Sync'd Salesforce" Standard β€” you build columns Filtered β€” saved WHERE Random β€” % A/B sample Shared β€” across BUs Synchronized β€” read-only CRM mirror Salesforce DE β€” sendable copy Sync DE β†’ build a Salesforce DE from it to make it sendable
SPF Β· DKIM Β· DMARC SPF "who may send" (IP list) DKIM "signed + untampered" DMARC "align + policy + report" SAP sets SPF + DKIM Β· you add DMARC (TXT) Β· DKIM aligns to the visible From domain

πŸ”‘ Core in 60 seconds

  • Studios DO, Builders DEFINE. Email/Mobile/Web/Automation act; Contact/Journey/Content/Analytics set up.
  • One human = one Contact Key = same Subscriber Key. All Contacts βŠ‡ All Subscribers. Key is sacred β€” never the email, use the MOD id.
  • DEs hold data; SQL/imports shape it; Automation Studio runs it on a schedule. Sendable DE = "Is Sendable" + field linked to _SubscriberKey.
  • AMPscript pulls fields at send time: Lookup = 1 value, LookupRows = set, LookupOrderedRows = sorted set (≀2,000).
  • Send Classification = Sender (face) + Delivery (truck). Transactional sends ignore unsubscribe (OTP/statements must arrive).
  • Journey = Entry β†’ Wait/Decision β†’ Activities β†’ Goal. Version-locked once activated; re-publish for changes.
  • Distributed Marketing = central brain, local hands: advisor picks journey, personalizes, submits for approval, sends.
  • Deliverability = SAP (SPF+DKIM by Salesforce) + DMARC (you). DKIM aligns to the visible From domain.
  • APIs: REST for speed/JSON (/data, /messaging, /interaction), SOAP for full object CRUD + Retrieve. OAuth2 v2/token, token is short-lived (~20 min β€” read expires_in).
  • Metrics from Data Views: _Sent _Open _Click _Bounce _Subscribers _Job. Support = INC β†’ triage β†’ RCA loop β†’ SLA.

🧩 Mnemonics & memory hooks

Every mnemonic from C01–C12, in one list:

  • Studios vs Builders β†’ "Build it, then Studio-use it." Builders are nouns, Studios are verbs.
  • The Studios β†’ "Every Morning Web Admins Automate" (E-M-W-A): Email, Mobile, Web, Automation. An admin every morning automates the channels.
  • Contact vs Subscriber β†’ "Same key, two hats." One person, one key β€” put on the email hat and it's the Subscriber Key.
  • Data Views β†’ "SOCBS" (or "SOCUB-J" with Job): Sent, Open, Click, (Unsub), Bounce, Subscribers, Job. "Send Often, Check Bounces, Suppress."
  • DE types β†’ "Stan Filled Random Shared Sync'd Salesforce" (Standard/Filtered/Random/Shared/Synchronized/Salesforce). Six drawers in the data cabinet.
  • Make a DE sendable β†’ "TICK + LINK": TICK "Is Sendable", then LINK the field to _SubscriberKey. "Tick the box, link the soul."
  • Field config β†’ "P.N.R.D." ("pin-ride"): Primary key? Nullable? Required? Default/Data-type/length. PNRD every column before you save.
  • All Subscribers statuses β†’ "A-HUB": Active, Held, Unsubscribed, Bounced. Every contact parks in the A-HUB.
  • SQL update types β†’ "OUA = Obliterate, Upsert, Add": Overwrite, Update (upsert), Append.
  • Join key β†’ "Same person, same SEND": SubscriberKey + JobID. Who + which send.
  • AMPscript lookups β†’ "One, many, many-sorted": Lookup / LookupRows / LookupOrderedRows.
  • Rows loop β†’ "C-R-F = Count, Row, Field": RowCount β†’ Row(@rs,i) β†’ Field(@row,"Col"). Count the Rows, Fetch each Field.
  • AMPscript block β†’ "V-S-I-O = VAR, SET, IF, Output." Very Smart If Output.
  • Safe output β†’ "V for visible, E for empty-check": wrap in v(), guard with Empty()/IIF().
  • The wall β†’ "two grand and you're grounded": ordered lookups cap at 2,000 rows.
  • Send Classification β†’ "S-D-C = Sender, Delivery, Compliance." Who / How / Legal.
  • Sender vs Delivery β†’ "Sender = the FACE, Delivery = the TRUCK." Face = From/Reply-to; Truck = IP, domain, footer.
  • Send modes β†’ "U-T-T = User, Triggered, Transactional." You Type, Trigger Trips, Trans Talks.
  • Commercial vs Transactional β†’ "Transactional = no unsubscribe."
  • Content Builder β†’ "TSB = Templates have Slots, Slots hold Blocks." Russian-doll: T βŠƒ S βŠƒ B.
  • QA checklist β†’ "PRLACVP" = "PuRe LACK of VP" (no VP signs off if QA fails): Preview, Render, Links, Audience, Classification, Volume, Personalization.
  • Compliance four β†’ "FUSS" (make a FUSS before any finance send): Footer (address), Unsub link, Sender/classification, Suppression applied.
  • Deploy promotion β†’ "D-Q-P, Package, Pin": Dev β†’ QA β†’ Prod via Package Manager, Pin in Git.
  • Render killers β†’ "OLD": Outlook (Word engine), Length/clipping (Gmail 102 KB), Dark mode. OLD clients break new emails.
  • Distributed Mktg plumbing β†’ "PCJ": Package (managed), Connect (Marketing Cloud Connect), Journey (Builder). PB&J connects two clouds.
  • What an advisor does β†’ "P-A-S-S": Pick journey β†’ Add/personalize β†’ Submit for approval β†’ Send. An advisor needs a PASS to talk to clients.
  • DM value prop β†’ "Central Brain, Local Hands."
  • DM sender β†’ "FROM = Name + Email": sendFromName + sendFromEmail in the Entry DE.
  • Quick Send vs Add-to-Journey β†’ "1 vs Many."
  • REST vs SOAP β†’ "REST is Fast/JSON, SOAP is Full/XML." REST to do, SOAP to define.
  • OAuth β†’ "Client gives ID+Secret, gets a short-lived Bearer." Token β‰ˆ 20 min (v2/token). (Legacy v1 /requestToken was ~1 hour β€” don't confuse them.)
  • Deliverability stack β†’ "SPF Says who, DKIM Signs, DMARC Decides."
  • RCA loop β†’ "REPAIR-VP" (RIRFVP): Reproduce, Isolate layer, Root-cause (5-Whys), Fix, Verify, Prevent. Hook: you're the VP of Repair β€” you prevent, not just patch.
  • Ticket priority β†’ "P1 = Page now": P1 down/compliance, P2 major, P3 minor, P4 cosmetic. Lower number = louder pager.

πŸ’€ Skeletons to memorize

1) AMPscript lookup + safe default (the FinServ workhorse):

%%[
  VAR @first, @advisor
  SET @first = AttributeValue("FirstName")
  IF Empty(@first) THEN SET @first = "Valued Client" ENDIF
  SET @advisor = Lookup("Advisors","AdvisorName","ContactKey", _subscriberkey)
  IF Empty(@advisor) THEN SET @advisor = "your Gap Financial team" ENDIF
]%%
Dear %%=v(@first)=%%, your advisor %%=v(@advisor)=%% has an update.

πŸ” Line by line: - VAR @first, @advisor β€” declare variables up top (V of V-S-I-O). - SET @first = AttributeValue("FirstName") β€” read the sendable-DE column for this subscriber; returns "" if missing (no error). - IF Empty(@first) THEN ... ENDIF β€” fallback so you never render "Dear ,". - Lookup("Advisors","AdvisorName","ContactKey", _subscriberkey) β€” cross-DE join: get AdvisorName from the Advisors DE where ContactKey = the built-in _subscriberkey. - %%=v(@first)=%% β€” v() outputs the variable into the rendered HTML.

2) Dedup SQL β€” keep the freshest row per subscriber:

SELECT SubscriberKey, EmailAddress, ModifiedDate
FROM (
  SELECT SubscriberKey, EmailAddress, ModifiedDate,
         ROW_NUMBER() OVER (PARTITION BY SubscriberKey ORDER BY ModifiedDate DESC) AS rn
  FROM Master_Contacts
) x
WHERE rn = 1

πŸ” Line by line: - ROW_NUMBER() OVER (PARTITION BY SubscriberKey ORDER BY ModifiedDate DESC) β€” number rows within each subscriber, newest first. - AS rn β€” name that number. - WHERE rn = 1 β€” keep only the single freshest row per subscriber = deduped audience.

3) Suppression join β€” exclude opt-outs before a finance send:

SELECT a.SubscriberKey, a.EmailAddress, a.FirstName
FROM   Audience a
LEFT JOIN Suppression s ON a.SubscriberKey = s.SubscriberKey
WHERE  s.SubscriberKey IS NULL
  AND  a.OptInStatus = 'Subscribed'

πŸ” Line by line: - LEFT JOIN Suppression s β€” attach any suppression match to each audience row. - WHERE s.SubscriberKey IS NULL β€” keep only rows with NO suppression match (anti-join = exclude suppressed). - AND a.OptInStatus = 'Subscribed' β€” belt-and-braces: only consented contacts.

4) OAuth token request (REST):

curl -X POST https://YOURSUBDOMAIN.auth.marketingcloudapis.com/v2/token \
  -H "Content-Type: application/json" \
  -d '{"grant_type":"client_credentials","client_id":"XXX","client_secret":"YYY","account_id":"MID"}'

πŸ” Line by line: - POST .../v2/token β€” the tenant-specific OAuth2 endpoint (subdomain comes from your Installed Package). - grant_type":"client_credentials" β€” server-to-server flow (no user login). - client_id / client_secret β€” the credentials from the Installed Package's API Integration component. - account_id":"MID" β€” optional Business Unit MID to scope the token to a child BU. - Response gives access_token (use as Authorization: Bearer ...) and expires_in (short-lived, ~20 min β€” read it, don't hardcode).

πŸ› οΈ In practice (what you would actually click / do)

  • Build a sendable DE: Email Studio β†’ Subscribers β†’ Data Extensions β†’ Create β†’ Standard β†’ name it β†’ in the create wizard tick Is Sendable, set Send Relationship = your key field ↔ Subscriber Key, email field ↔ Email Address β†’ set Retention for compliance β†’ Save.
  • Write + run SQL: Automation Studio β†’ Activities β†’ SQL Query β†’ write the dedup/suppression query β†’ set Target DE + update type (Overwrite/Update/Append) β†’ Save β†’ drag into an Automation β†’ schedule or trigger via File Drop β†’ Run Once to test β†’ check the target DE row count.
  • Personalize + preview: Content Builder β†’ open the email β†’ drop AMPscript in an HTML block β†’ Preview & Test β†’ pick a specific subscriber/DE row β†’ confirm @advisor resolves, no empty greeting β†’ send a test send to your seed list.
  • Build a journey: Journey Builder β†’ Create New Journey β†’ Entry Source = the sendable DE (set evaluation/refresh) β†’ drag Wait, Decision Split (e.g., Opened?), Email activities β†’ set Goal β†’ Validate β†’ Activate (locks the version).
  • Distributed Marketing send: advisor opens DM in Sales/Service Cloud β†’ Use a Journey / Quick Send β†’ picks the marketer-approved journey β†’ personalizes the message β†’ Submit for approval β†’ on approval it sends from sendFromName/sendFromEmail.
  • Set up an API integration: Setup β†’ Installed Packages β†’ New β†’ add an API Integration (OAuth2) component β†’ copy Client Id/Secret + the auth/rest base URIs β†’ POST to v2/token β†’ call /data/v1/... or /interaction/v1/... with the Bearer token.
  • Deploy promotion: build in Dev BU β†’ QA validates with the PRLACVP/FUSS checklist β†’ move assets via Package Manager (or Deployment Manager) Devβ†’QAβ†’Prod β†’ tag/pin the version in Git.
  • RCA on a failed send: Automation Studio β†’ check the Automation's Activity / error log β†’ reproduce with one row in Preview β†’ trace whether it's data (DE), logic (AMPscript/SQL), or integration (API/Connect) β†’ fix β†’ re-run β†’ write the postmortem.

🎀 Rapid-fire

Q1. Contact Key vs Subscriber Key? β†’ Same string for one human; Contact Key is the account-wide id, Subscriber Key is the email-channel id.

Q2. How do you make a DE sendable? β†’ Tick "Is Sendable" and link a field to All Subscribers _SubscriberKey. …and in practice: I do it in the DE create wizard's Send Relationship step in Email Studio.

Q3. Lookup vs LookupRows vs LookupOrderedRows? β†’ One value / a set / a sorted set (≀2,000 rows).

Q4. How do you dedup an audience? β†’ ROW_NUMBER() OVER (PARTITION BY key ORDER BY date DESC) then WHERE rn = 1. …and in practice: I run it as a SQL Query activity into a clean target DE in Automation Studio.

Q5. Three SQL update types? β†’ Overwrite (truncate+insert), Update (upsert on PK), Append (insert only).

Q6. Commercial vs transactional send? β†’ Transactional (OTP, statements) ignores unsubscribe and must be delivered; commercial honors opt-out.

Q7. What locks when you activate a journey? β†’ The version is locked; to change logic you create/publish a new version. …and in practice: I pause/stop, copy to a new version, edit, validate, re-activate.

Q8. REST vs SOAP in SFMC? β†’ REST = fast JSON for sends/data/journeys; SOAP = full object CRUD + Retrieve with paging. …and in practice: I use REST /data/v1 for DE rows, SOAP Retrieve for bulk object reads.

Q9. How long does an OAuth token last and how do you get one? β†’ short-lived, ~20 min (read expires_in; no refresh token β€” just re-request); POST client_id/secret to the tenant v2/token endpoint, then send Authorization: Bearer.

Q10. SAP vs DMARC β€” who sets what? β†’ Salesforce SAP configures SPF + DKIM for your sending domain; you add the DMARC TXT record. DKIM aligns to the visible From domain.

Q11. Where do email metrics live? β†’ Data Views (_Sent, _Open, _Click, _Bounce, _Subscribers, _Job) joined on SubscriberKey + JobID. …and in practice: I SQL the Data Views into a reporting DE feeding Analytics Builder.

⚠️ Gotchas / RCA hooks

  • Empty personalization / "Dear ," in production β†’ missing column or failed Lookup. RCA: Preview the exact row, check the source DE field and the Lookup key match; add Empty() fallbacks.
  • Send excludes people you expected β†’ wrong send relationship, unmatched Subscriber Key, or over-broad suppression. RCA: count rows in the sendable DE vs the suppression anti-join.
  • Journey won't pick up new contacts β†’ entry-source evaluation/refresh not set, or contacts already went through. RCA: check entry DE refresh schedule + re-entry rules.
  • DMARC fails even though SPF "passes" β†’ SPF passes the SAP bounce domain, not the From domain. RCA: rely on DKIM alignment to the From domain; confirm the DMARC TXT and DKIM CNAME records.
  • 401 from the API β†’ token expired (~20 min) or wrong BU MID. RCA: re-request token, scope to correct account_id, confirm the Installed Package scopes.
  • Automation failed overnight β†’ file didn't drop, SQL target locked, or a query timed out. RCA: open the Automation error log, reproduce the SQL on a small set, check the import file path/SFTP.
  • Duplicate sends β†’ un-deduped audience or journey re-entry. RCA: add the ROW_NUMBER dedup and tighten re-entry to "no re-entry."

➑️ Next: C14_Practical_Drills_and_Mock.md

C14 β€” Practical Drills & Mock (the LTM-gap fix)

🎯 Why Coforge cares: the role is a hands-on Technical Lead β€” build/validate/deploy campaigns, fire journeys, fix INC tickets, run RCA under SLA. They will ask "show me HOW," not "what is it." This module turns your theory into click-paths.

🧠 One-screen mental model

        EVERY PRACTICAL ANSWER = 3 LAYERS
        β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
   (a)  β”‚ THEORY      β†’ "what it is" (1 sentence, no more)β”‚
        β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
   (b)  β”‚ PRACTICAL   β†’ "here is exactly what I click /   β”‚  ← they want THIS
        β”‚               write / run"  (the click-path)   β”‚
        β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
   (c)  β”‚ GOOD vs WEAKβ†’ "I also verify X / suppress Y"    β”‚  ← seniority signal
        β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                 |
                 v
   THE TELL: stop after 1 theory line, then say
   "...and the way I'd actually do that is β€” go to X > click Y > ..."

πŸ”‘ Core in 60 seconds

  • The fix for "too theoretical" = after one definition sentence, pivot with "...and the way I'd actually do it is β€”" then narrate clicks.
  • Always name the exact place: Studio > screen > button. Vague = weak.
  • Always end practical answers with a verify step (Preview, Validate, test send, Tracking, query row count).
  • For financial services, every send answer must mention suppression + compliance + approval.
  • Mock yourself on a timer (90s/answer). The LTM gap was pacing + concreteness, not knowledge.

🧩 Mnemonics & memory hooks

  • The 3 layers = "T-P-G" β†’ "Theory, then Prove it, then Good-vs-weak." Say the prove-it part out loud always.
  • Every send = "BAT-VS-D" β†’ Build β†’ Audience β†’ Test β†’ Validate β†’ Send β†’ Deliverability check. "A BAT VS a Dragon."
  • RCA = "5W + Fix + Prevent" β†’ What broke, When, Where, Who-hit, Why, Fix, Prevent-recurrence. "Five W's, Fix, Forever."
  • Debug blank personalization = "DARTS" β†’ Data present? Attribute name spelled right? Relationship (sendable DE)? Typo/case? SubscriberKey match? "Throw DARTS at blank fields."
  • Deliverability drop = "CRABS" β†’ Content/spammy, Reputation/IP, Authentication (SPF/DKIM/DMARC), Bounces/list hygiene, Suppression/complaints. "CRABS crawl into your inbox placement."

πŸ’€ Skeletons to memorize

1. Dedup query (keep newest row per SubscriberKey)

SELECT SubscriberKey, EmailAddress, AdvisorID, ModifiedDate
FROM   Lead_Staging
QUALIFY ROW_NUMBER() OVER (
          PARTITION BY SubscriberKey
          ORDER BY ModifiedDate DESC
       ) = 1

πŸ” Line by line: - SELECT ... β€” the columns you want in the clean target DE. - FROM Lead_Staging β€” the raw/duplicated source DE. - QUALIFY ROW_NUMBER() OVER (...) β€” SFMC SQL supports QUALIFY; it filters on a window function without a sub-query. - PARTITION BY SubscriberKey β€” restart the count for each unique person. - ORDER BY ModifiedDate DESC β€” newest record gets number 1. - = 1 β€” keep only the freshest row per person; drop the dupes. - (Fallback if QUALIFY is blocked in your stack: wrap it as a sub-query and WHERE rn = 1.)

2. Fire a journey via API (entry event)

POST https://YOURSUBDOMAIN.rest.marketingcloudapis.com/interaction/v1/events
Authorization: Bearer <OAuth access_token>
Content-Type: application/json; charset=UTF-8

{
  "ContactKey": "ADV-10293",
  "EventDefinitionKey": "APIEvent-advisor-onboard",
  "Data": { "AdvisorID": "10293", "Tier": "Platinum" }
}

πŸ” Line by line: - POST /interaction/v1/events β€” the Journey Builder "fire entry event" REST endpoint. - Authorization: Bearer β€” token from /v2/token (Server-to-Server installed package). - Content-Type ... charset=UTF-8 β€” required when payload has non-ASCII (names/accents). - ContactKey β€” the subscriber being injected; must match the journey's contact model. - EventDefinitionKey β€” copied from the journey's API Event entry source config (NOT the journey name). - Data{} β€” must match the journey's entry-source data schema attributes exactly, or the contact won't enter. - Success = HTTP 201 with an eventInstanceId; 400 = bad key or inactive contact.

3. AMPscript "never blank" personalization guard

%%[ VAR @fname
    SET @fname = AttributeValue("FirstName")
    IF Empty(@fname) THEN SET @fname = "Valued Client" ENDIF
]%%
Dear %%=v(@fname)=%%,

πŸ” Line by line: - VAR @fname β€” declare the variable first (undeclared = silent blank). - AttributeValue("FirstName") β€” pulls from the sendable DE / subscriber attribute by exact name. - IF Empty(@fname) β€” catches NULL and empty string. - SET ... "Valued Client" β€” compliant fallback; never ship "Dear ,". - %%=v(@fname)=%% β€” v() outputs the variable in the email body.

πŸ› οΈ In practice (what you would actually click / do)

This is the section that fixes your interview. For each, say the click-path out loud.

A. Build + send a campaign (the full BAT-VS-D)

  • Build: Email Studio > Content Builder > Create > Email > pick template > drop AMPscript/dynamic blocks.
  • Audience: target a sendable Data Extension (has SubscriberKey relationship). For FS, apply a suppression/exclusion DE (opt-outs, do-not-contact, compliance holds).
  • Test: Preview & Test tab > load a test subscriber row > check personalization renders > Send Test to seed list.
  • Validate: check links, subject/preheader, AMPscript errors, and Validate during send setup.
  • Send / schedule: Send flow > select DE + suppression > schedule or send. For repeatable: build in Automation Studio as a Send Email activity.
  • Deliverability check: after send, Tracking tab > Sent/Delivered/Bounce/Open/Click; investigate any bounce spike.

B. Write + run a dedup query

  • Automation Studio > Activities > SQL Query > paste the QUALIFY skeleton.
  • Target DE = clean DE; Update or Overwrite action.
  • Run Once to validate, then check target DE row count vs source β€” confirm dupes dropped.
  • Drop the Query activity into an Automation so it runs on schedule before the send.

C. Debug blank personalization (throw DARTS)

  • Reproduce in Content Builder > Preview & Test with the failing subscriber.
  • Data: query the sendable DE β€” is the value actually populated for that SubscriberKey?
  • Attribute: is the AMPscript field name spelled/cased exactly as the DE column?
  • Relationship: is it a sendable DE with the right subscriber relationship?
  • Typo: %%FirstName%% vs %%=v(@FirstName)=%% β€” declared variable?
  • SubscriberKey: does send context's key match the data row's key? Add an Empty() fallback so it never ships blank again.

D. Fire a journey via API

  • Journey Builder > journey > entry source = API Event > copy the Event Definition Key.
  • Make sure an installed package (Server-to-Server) gives Journeys API scope; get token from /v2/token.
  • POST the payload (skeleton #2). Confirm 201, then in the journey watch the entry count tick up / check the contact in Journey History.

E. Set up an A/B test

  • Content Builder send / Email Studio > A/B Test > choose variable: Subject Line, Content, From Name, or Send Time.
  • Set test % split (e.g., 10%/10%), pick winner metric (Open or Click), set wait duration, then auto-send winner to remaining 80%.
  • Validate both treatments preview correctly; confirm same suppression applies to both.

F. Create a sendable DE + send relationship

  • Email Studio > Subscribers > Data Extensions > Create (or from a template).
  • Tick Is Sendable; map the DE field that holds the address, and set Sendable Relationship: DE field ⇄ Subscriber Key (Subscribers on Subscriber Key).
  • Add a Primary Key (usually SubscriberKey) and an EmailAddress field. Now it appears as a send target.

G. Troubleshoot a failed automation

  • Automation Studio > Activities/automation > open the run history / Activity > read the error message.
  • Common: SQL syntax/timeout, file-drop file not arrived, DE field length, locked DE.
  • Fix the activity, Run Once to confirm green, then re-enable schedule. Log RCA on the INC ticket.

H. RCA a deliverability drop (CRABS)

  • Pull Tracking + reputation: Open Rate / Bounce / Complaint trend.
  • Content (spam words/image-heavy), Reputation (IP/domain), Auth (SPF/DKIM/DMARC failing), Bounces (bad list hygiene), Suppression/complaints rising.
  • Use Email Studio > Bounce Mail Management + Deliverability tools; check sender authentication (SAP). Document 5W+Fix+Prevent.

I. Build an advisor Distributed Marketing send

  • Distributed Marketing (managed package in the CRM, e.g., Financial Services Cloud) β€” needs Journey Builder + an FSC/Sales/Service license.
  • Marketer builds + approves a campaign in SFMC; surfaces it as a DM campaign on the CRM record (e.g., a Financial Account / Client).
  • Advisor opens the client record > Quick Send (one email, personalized) or adds the client to a Journey > advisor personalizes within brand guardrails > sends.
  • The advisor never logs into SFMC; data + branding stay centrally controlled (compliance win).

🎀 Rapid-fire

  • Q: How do you make sure a personalization token never renders blank? A: Declare a VAR, pull with AttributeValue, wrap in IF Empty() THEN fallback. …and in practice: I reproduce it in Content Builder Preview & Test with the failing SubscriberKey before shipping the fix.

  • Q: Dedup a DE? A: ROW_NUMBER() OVER (PARTITION BY key ORDER BY date DESC) = 1. …and in practice: SQL Query activity > target a clean DE > Run Once > compare row counts.

  • Q: How does an external system push someone into a journey? A: POST to /interaction/v1/events with ContactKey + EventDefinitionKey. …and in practice: I copy the Event Definition Key off the API Event entry source and confirm a 201 + rising entry count.

  • Q: A/B test what and how? A: Subject, content, from-name or send-time; split %, winner metric, wait, auto-send winner. …and in practice: Email Studio A/B Test wizard, 10/10 split, winner by open rate.

  • Q: What makes a DE sendable? A: Is-Sendable flag + a send relationship mapping its key to Subscriber Key. …and in practice: Data Extensions > Create > tick Is Sendable > map field ⇄ Subscriber Key.

  • Q: Automation failed overnight β€” first move? A: Open run history, read the activity error, fix, Run Once, re-enable, log RCA. …and in practice: I check the failing step's error text first β€” usually SQL timeout or a file-drop that didn't land.

  • Q: Open rate dropped 40% β€” RCA? A: CRABS β€” Content, Reputation, Auth, Bounces, Suppression/complaints. …and in practice: Tracking trend + Bounce Mail Management + verify SPF/DKIM/DMARC, then write 5W+Fix+Prevent.

  • Q: How do advisors send without SFMC access? A: Distributed Marketing β€” marketer approves, advisor Quick Sends or adds to a Journey from the CRM record. …and in practice: managed package on the FSC client record; advisor personalizes inside brand guardrails, never logs into SFMC.

⚠️ Gotchas / RCA hooks

  • Blank fields: undeclared variable or a non-sendable DE β†’ always Preview with the real failing row, never a happy-path one.
  • Journey API 400, not 201: wrong EventDefinitionKey (people use the journey name) or contact inactive / data schema mismatch β†’ re-copy the key, match the entry-source attributes exactly.
  • Dedup keeps the wrong row: ORDER BY direction wrong, or NULL dates sort last β†’ coalesce/handle NULLs, confirm DESC = newest.
  • A/B winner never sends: wait window too short or remaining-audience setting off β†’ check winner criteria + holdout config.
  • Automation "succeeded" but no emails: SQL ran but matched 0 rows, or wrong target DE β†’ always check row counts, not just the green check.
  • Deliverability drop blamed on content but it's auth: check SPF/DKIM/DMARC + IP reputation before rewriting copy.
  • FS compliance trap: forgot the suppression/exclusion DE β†’ opt-outs or do-not-contact get mailed. Every send answer: "...applied against the suppression DE."
  • Interview pacing trap (the real LTM gap): you over-explain theory and run out of time. Cap theory at one sentence; spend the rest on the click-path. Practice on a 90s timer.

⏱️ Timed practical mock (set a 20-min timer β€” 90s/answer)

Read the Q, speak the answer aloud, then peek at the model. Score yourself with the rubric.

  1. Walk me through building and sending a campaign end to end. β†’ BAT-VS-D: Content Builder build > sendable DE + suppression > Preview & Test seed > Validate > schedule/Automation > Tracking check.
  2. Write me a query that removes duplicate subscribers. β†’ ROW_NUMBER() PARTITION BY SubscriberKey ORDER BY ModifiedDate DESC = 1; run as SQL Query activity, compare row counts.
  3. A token is rendering blank in production β€” debug it live. β†’ DARTS; reproduce in Preview with the failing key; add IF Empty() THEN fallback.
  4. An external app needs to drop advisors into an onboarding journey. β†’ POST /interaction/v1/events, ContactKey + EventDefinitionKey + Data schema; confirm 201 + entry count.
  5. Set up an A/B subject-line test. β†’ A/B wizard, 10/10 split, winner = open rate, wait window, auto-send winner to 80%.
  6. Create a sendable DE for a new advisor list. β†’ Data Extensions > Create > Is Sendable > map address field + Subscriber Key relationship.
  7. A nightly automation failed β€” what do you do? β†’ Open run history, read the failing activity's error, fix, Run Once green, re-enable, log RCA on the INC.
  8. Open rates dropped sharply this week β€” run the RCA. β†’ CRABS; Tracking trend + Bounce Mail Management + check SPF/DKIM/DMARC; write 5W+Fix+Prevent.
  9. How do you let financial advisors send branded emails without SFMC logins? β†’ Distributed Marketing on the FSC record; marketer approves, advisor Quick Send or add-to-Journey within guardrails.
  10. A send went out with a wrong personalization β€” what's your INC + RCA response? β†’ Acknowledge under SLA, identify scope (which SubscriberKeys), root cause (data/attribute/relationship), corrective send if needed, document Fix + Prevent (add Empty() guard + Preview-with-failing-row step).
  11. How do you validate a campaign before deployment? β†’ Preview & Test with real rows, Send Test to seed, Validate in send flow, confirm suppression + links + AMPscript, dual approval for FS.
  12. Show me how you'd schedule a recurring data load + send. β†’ Automation Studio: File Drop/SFTP import > SQL dedup Query > Send Email activity, scheduled; monitor run history.

πŸ“Š Scoring rubric (per answer, out of 3):

Score What it sounds like
0 Definition only / "it depends" β€” no clicks
1 Right concept, vague on where/how
2 Names the exact Studio + screen + steps
3 Steps + a verify step + a compliance/suppression mention
  • Target: average 2.5+. Anything scoring ≀1 = you slipped back into theory β€” redo it leading with "...and the way I'd actually do it is β€”".

➑️ Next: (final β€” the morning of the interview, re-read C13 Memory Vault, then breathe. You've got this, Akash! πŸš€)

β˜… Marked for Review

Sections you flagged with the β˜† Mark button in the bar above (or the M key) while studying. Click any item to jump straight back to it. This list is saved in your browser and updates automatically.