Salesforce authenticates server-to-server integrations with a signed JWT, not a password — and MailInApp's API data source speaks that flow natively. Connect once, and a KPI scorecard or chart block can bind straight to live Opportunity, Account, or Contact rows, no refresh token to babysit and no CSV to re-export before every send.
Most "weekly pipeline" emails are a screenshot of a report, stale the moment someone pastes it in. Binding a chart block directly to a Salesforce-backed data source means the block's own number comes from a real SOQL query — and a recurring send re-runs that query fresh on every send, so Monday's digest actually reflects Monday's pipeline.
How the connection works
MailInApp
Signs a JWT with your Connected App's private key
Salesforce token endpoint
Verifies the signature, returns an access token
Salesforce REST API
Runs your SOQL query, Bearer-token authenticated
Your email
KPI scorecard & chart blocks bound live to the rows
Every step happens server-side on each send. No password is ever sent, and there's no refresh token — a stale token is replaced by signing a fresh assertion.
This is the same JWT Bearer flow Salesforce documents for its own server-to-server integrations, wired into MailInApp's existing OAuth2 auth modes for API data sources rather than a bespoke Salesforce-only integration.
Set up a Connected App once
In Salesforce Setup, create a Connected App, enable OAuth settings, and upload a self-signed certificate under Use digital signatures — the certificate goes to Salesforce, the paired RSA private key goes to MailInApp. Set Permitted Users to Admin approved users are pre-authorized, which is what makes the exchange non-interactive: there's no consent screen for a script to click through. Note the Connected App's Consumer Key and your org's My Domain URL — both go into the connection in MailInApp.
Point it at a SOQL query
The data source's Endpoint is a REST query URL, and the query string is the actual data you get back:
SELECT Name, Amount, StageName, CloseDate FROM Opportunity WHERE IsClosed = false
Set Data path to records — Salesforce wraps its query results in a records array. Relationship fields like Owner.Email come back nested and get dropped by MailInApp's row parser, so keep the query flat; select OwnerId instead if you need an owner identifier to filter or merge on later.
Bind blocks straight to it, not merge tags
Add the connection to a project from the studio's Data panel with a collection role — the same binding a repeat block uses. From there, KPI scorecard, bar, line, and pie chart blocks can bind directly to it in their own Inspector:
- A KPI scorecard set to
Amountwith a Sum aggregate becomes a live "total open pipeline" figure. - A bar chart grouped by
StageName, withAmountas its series (Sum aggregate again), becomes a pipeline-by-stage breakdown.
Neither block needs a single merge tag typed by hand — the binding does the work, and both stay correct as deals move stage or close.
Send it on a schedule
A recurring weekly send re-runs the SOQL query and re-renders both blocks against Salesforce's current rows every time it fires — the same digest structure, fresh numbers each Monday, with nobody rebuilding it by hand. A Button block pointed at each Opportunity's Salesforce URL gives anyone reading the digest a one-click way to open the record behind a number that catches their attention.
Getting started
Create a Salesforce Connected App with a certificate for the JWT Bearer flow, connect it in MailInApp's Data Sources tab with your Consumer Key, integration username, and private key, point the endpoint at a SOQL query with records as the data path, then bind a KPI scorecard and bar chart to it from the studio's Data panel. See the Salesforce integration guide for the full field-by-field setup.