Send email from a user's Gmail or Outlook with OAuth
· SyncYak team
Your app sends email on behalf of users: an agent's follow-up, a recruiter's reply, a client's invoice reminder. For years the easy way to do it was to ask for the user's mailbox password, or an app password, and speak SMTP. That path is narrowing, and if your product still depends on it, this is a good month to plan the move.
This post covers what is changing at Microsoft, how OAuth sending differs from SMTP with a stored password, and a worked example of sending from a connected mailbox and handling the replies.
What is changing for Microsoft 365
Microsoft has been retiring Basic authentication for SMTP client submission in Exchange Online for a while, and the schedule has moved. According to Office 365 for IT Pros, Basic authentication for SMTP AUTH will be disabled by default at the end of December 2026, tenant administrators will be able to turn it back on, and Microsoft plans to announce a final removal date in the second half of 2027. New tenants created from January 2027 will not be able to use Basic authentication with SMTP AUTH and must use OAuth.
Read that carefully. Nothing breaks overnight, and an administrator can re-enable the old behavior. But "an administrator can switch it back on" is a poor foundation for a product. Some customers' IT teams will leave it off, and new tenants will not have the option at all. Check Microsoft's own announcements for the current dates before you commit to a plan, because they have changed once already.
Why OAuth is better for you, not only for the admin
SMTP with a stored password has four problems that OAuth removes:
- You hold a secret that unlocks a whole mailbox. A leaked password or app password exposes the user's entire inbox. An OAuth grant is scoped to the permissions the user approved and can be revoked from the provider's side.
- Consent is explicit. The user sees which app is asking and what it can do. With your own registered Google and Microsoft apps, the consent screen carries your product's name.
- Revocation works. If someone leaves a company, the admin revokes the app and your access ends. You do not have to find and rotate a password.
- No credential handling in your database. You store a grant identifier, not a password.
The cost of doing this yourself is real. You register apps with Google and Microsoft, build a connect flow, store and refresh tokens, handle expiry and revoked consent, and then write separate send and sync code for each provider.
What the flow looks like
With a hosted connect flow the sequence is short:
- Your user clicks "Connect mailbox" in your app.
- They land on a connect page, sign in with Google or Microsoft, and approve access.
- You receive a grant, which represents that one connected mailbox.
- You send and receive through one API using the grant id.
The send call is a single request. Here it is with curl:
curl -X POST https://api.syncyak.com/v3/grants/$GRANT_ID/messages/send \
-H "Authorization: Bearer $SYNCYAK_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"to": [{ "email": "[email protected]", "name": "Sam" }],
"subject": "Your showing on Saturday",
"body": "<p>See you at 10am at 42 Harbor Road.</p>"
}'
The message goes out from the connected mailbox's own address, so it lands in the recipient's inbox as a message from the person, not from a shared sending domain.
The same request in Node.js:
const res = await fetch(`https://api.syncyak.com/v3/grants/${grantId}/messages/send`, {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.SYNCYAK_API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
to: [{ email: '[email protected]', name: 'Sam' }],
subject: 'Your showing on Saturday',
body: '<p>See you at 10am at 42 Harbor Road.</p>',
}),
});
const { data } = await res.json(); // data.id is the sent message
Handle replies and bounces with webhooks
Sending is half of the job. A sequence that keeps emailing someone who already answered is worse than no sequence. Instead of polling mailboxes, subscribe to webhooks. SyncYak Mail posts events such as message.created for new mail, thread.replied for replies to a message you sent with reply tracking on, and message.bounce_detected when a send bounces. With tracking on, which starts on the Hobby plan, you also get open and click events. The email webhooks page lists the full set.
Two practical rules for the receiving endpoint:
- Verify the signature before you trust the payload. Each event carries an
X-Nylas-Signatureheader: the hex HMAC-SHA256 of the raw body with your webhook secret. Compute it over the raw bytes, not a re-serialized object, and compare in constant time. - Answer fast, work later. Return a 2xx once the event is stored and process it from a queue, so a slow CRM call does not cause redeliveries.
import crypto from 'node:crypto';
function verify(rawBody, signature, secret) {
const expected = crypto.createHmac('sha256', secret).update(rawBody).digest('hex');
const a = Buffer.from(expected);
const b = Buffer.from(signature || '');
return a.length === b.length && crypto.timingSafeEqual(a, b);
}
When a thread.replied event arrives, stop the sequence for that contact and alert a person. When message.bounce_detected arrives, flag the address so nobody keeps sending to it.
Before a destination receives events, SyncYak calls your URL with a challenge value and expects it back, so events never go to an address that is not yours. To develop all of this on your laptop, run a tunnel and use its public address as the destination while you build.
Mailboxes that cannot use one-click sign-in
Not every user has a Google or Microsoft account. Yahoo, iCloud, GoDaddy and other IMAP mailboxes connect with an app password instead of OAuth. The connect page detects the provider from the address, so your app shows one button and the page picks the right method. Treat app-password mailboxes as the exception in your own roadmap: they are the same class of credential that providers are moving away from.
How SyncYak helps
SyncYak Mail gives you the hosted connect page, the send API and the webhooks described above. The API follows the Nylas v3 request and webhook formats, so an existing Nylas integration switches by changing the API host, the client ID and the secret.
You bring your own Google and Microsoft apps, which keeps your product's name on the consent screen. On the Free plan you can connect 3 mailboxes and send 1,000 messages a month. Hobby is $12 a month for 10 mailboxes and 20,000 sends, with open and click tracking. Extra mailboxes are an add-on at $1.25 each. See pricing for every tier, and the Connect Gmail and Outlook page for the setup steps.
A short plan for this quarter
- List every place your product stores a mailbox password or app password.
- Register a Google app and a Microsoft app, and move Microsoft 365 users to OAuth first, since that is where the dates are moving.
- Subscribe to reply and bounce webhooks so you can stop polling.
- Keep IMAP with an app password only for providers that offer nothing else.
Ready to try it? Create a free account, connect a test mailbox and send your first message from it.