SendGrid dynamic templates for replies to Let's talk submitters, and for the internal support forward. Which email a submitter gets depends on the label the AI classification assigns. See ADR 0001 and the plan. Designs: Figma / Emails.
| Label | Template | Processor flow | SSM template id | Suggested subject | Figma |
|---|---|---|---|---|---|
COMMUNITY_OPPORTUNITY (looking for work) |
lets-talk-developer-getting-started.html |
lets-talk-community-opportunity-reply |
LETS_TALK_OPPORTUNITY_TEMPLATE_ID |
Getting started on Topcoder as a developer | 2853:1389 |
COMMUNITY_SKILLS (learning, practising) |
lets-talk-practice-learn-help.html |
lets-talk-community-skills-reply |
LETS_TALK_SKILLS_TEMPLATE_ID |
Practice, learn and get help on Topcoder | 2853:1485 |
COMMUNITY_GENERAL (no defined direction) |
lets-talk-community-general-reply.html |
lets-talk-community-general-reply |
LETS_TALK_GENERAL_TEMPLATE_ID |
Welcome to Topcoder | 2849:996 |
WIPRO_QUERIES (Wipro employees, Wipro-internal) |
lets-talk-how-crowdsourcing-works.html |
lets-talk-wipro-queries-reply |
LETS_TALK_WIPRO_TEMPLATE_ID |
How crowdsourcing works at Topcoder | 2853:1572 |
SALES_LEAD |
lets-talk-sales-reply.html |
lets-talk-sales-reply |
LETS_TALK_SALES_REPLY_TEMPLATE_ID |
Thank you for your interest in Topcoder | — (no design; uses the shared shell) |
COMMUNITY_SUPPORT (internal, to support) |
lets-talk-support-forward.html |
lets-talk-support-forward |
LETS_TALK_SUPPORT_TEMPLATE_ID |
Let's talk support request | — (no design; uses the shared shell) |
The other labels send no reply to the submitter:
JUNK: nothing is sent.COMMUNITY_SUPPORT: the submission is forwarded internally toLETS_TALK_SUPPORT_RECIPIENTS(defaultsupport@topcoder.com) with the support forward above. Its reply-to is the submitter, so support answers them by replying.UNKNOWN(classification failed): the existing internal Let's talk email toLETS_TALK_RECIPIENTS.
All five reply templates take firstName and viewInBrowserUrl; the sales reply also uses interestArea:
| Variable | Set by the processor | Notes |
|---|---|---|
firstName |
Yes, when usable | The submitter's first name: trimmed, whitespace collapsed, at most 40 characters. It is left out when it contains a URL, an @, digits or markup characters, and the template then greets "there". |
viewInBrowserUrl |
No | The "View this email in your browser" line is shown only when this is set. Transactional sends have no hosted web version, so the line stays hidden. |
interestArea |
Yes | The display label of the "What are you interested in?" option ("Crowdsourced Innovation", …). It comes from the form's fixed option list, so it's safe to show. Only the sales reply uses it ("I received your inquiry regarding …"); when it's missing the sentence reads "I received your inquiry and …". |
The processor sends nothing else to any reply template. No message, company, email address, URL or classification is ever part of the data (ADR 0001, Decision 5). A template that refers to any other variable renders it empty, so don't add variables without changing the processor first. This is what keeps the public form from being used to send attacker-written text from Topcoder's domain.
Use the double-brace form {{firstName}}, which SendGrid HTML-escapes. Never use triple braces {{{…}}}.
The support forward goes to Topcoder staff, not to the submitter, so it gets the full submission (see the processor README and examples/lets-talk-email.json):
| Variable | Notes |
|---|---|
answers.firstname, answers.lastname, answers.email, answers.company, answers.briefly_describe_your_inquiry |
As submitted. The inquiry keeps its line breaks (white-space:pre-wrap). |
answers.interested_in |
The option key (crowdsourcing, …). The template maps the three known keys to their display labels with {{#equals}}, and shows any other key as it is. |
fields |
Every answer as {key, value} strings, shown under "All answers". |
submissionId, submittedAt, sourcePage |
Submission metadata. |
classification |
label, confidence, needsReview, rationale, workflowRunId. The section is hidden when it's missing. |
All of these except the metadata and classification are attacker-controllable text, so the same rule applies: double braces only, and keep the subject fixed (don't put submitted values in it).
Do this for each template, in each environment (dev and production):
-
In SendGrid, go to Email API → Dynamic Templates → Create a Dynamic Template, named after the file (for example
lets-talk-developer-getting-started). -
Add Version → Blank Template → Code Editor. Paste the HTML file's content as it is. The images already point at the SendGrid CDN (see Images).
-
Set the Subject from the table above. The
<title>and preheader are already in the HTML. -
In Test Data, paste the sample below and check the preview, then check it again with
{}to see the "Hi there" fallback:{ "firstName": "Alex", "interestArea": "Crowdsourced Innovation" }For the support forward, use
payload.datafrom examples/lets-talk-email.json, with aclassificationadded:"classification": { "label": "COMMUNITY_SUPPORT", "status": "CLASSIFIED", "confidence": 0.8, "needsReview": false, "rationale": "Payment not received.", "workflowRunId": "6f1c2a9e-6b7d-4e8f-9a01-2b3c4d5e6f70" }
-
Send a test email to yourself from the editor and check it in at least Gmail and Outlook, on desktop and mobile.
-
Save, and make the version active.
-
Copy the template id (
d-followed by 32 hexadecimal characters) into the SSM SecureString/config/forms-processor-v6/appvar/<SSM template id>from the table, then redeploy the processor. Tasks read SSM only at startup.
A flow whose template id is missing doesn't send. Its deliveries wait and retry until the id is set, so templates can go live one at a time. A flow should only be enabled once its template is active (rollout: plan §5).
- Edit the HTML file here, and get the change reviewed.
- In SendGrid, add a new version of the same template with the new HTML, test it (steps 4–5 above), and make it active.
The template id doesn't change, so no SSM change or redeploy is needed. Keep the previous version, so you can switch back to it if needed.
All the templates in this folder share the same header, footer and mobile styles. Only the content card, <title> and preheader differ (the support forward also adds two mobile rules for its label/value tables). A change to the shared shell (logo, footer, social links, styles) must be made in every file and published as a new version of every template.
The logo and social icons are hosted on the SendGrid CDN. Their URLs are in assets/icons.txt and are already used, over https, in the HTML. assets/ keeps the source PNGs: 2x exports from Figma, displayed at 204×48 (logo) and 32×32 (icons). To replace an image, upload it to the SendGrid Design Library, then update its URL in icons.txt and in every HTML file.
The Figma designs don't include these links, so check them first:
- "sign up here" (general reply, developer getting started):
https://accounts-auth0.topcoder.com/?mode=signUp. The practice email's "create your free account" links tohttps://www.topcoder.com/, as in its design. - The social links: Facebook, YouTube, LinkedIn, Twitter and Instagram (
https://discord.com/invite/topcodercomes from the designs). - The
SALES_LEADtemplate has no Figma design; it follows the shared shell. Its signature andmailto:are Kiril Kartunov's (hard-coded), while replies go to the firstLETS_TALK_SALES_REPLY_TOaddress (defaultsupport@topcoder.com; the rest, defaulttest1@topcoder.com, are copied). Set that list for production so the first address is the signer's.