Maildriply
All posts
8 min readby Maildriply Team

Gmail API vs. SMTP for Cold Email — The Developer's Guide to Deliverability

Building a sending or outreach pipeline? Discover the technical, security, and deliverability differences between Gmail API OAuth2 and traditional SMTP relays.

engineeringgmaildeliverabilitysmtp
Illustration of paper airplanes leaving a leaky winding pipe and a straight locked tube

For an app that sends email from its users' Gmail accounts, the Gmail API is the better choice than SMTP. It can send with the narrow gmail.send OAuth scope, while Gmail's SMTP server needs either a password (no longer accepted for Google Workspace accounts since March 14, 2025) or the full-mailbox https://mail.google.com/ scope. It also returns structured errors your queue can act on. Third-party SMTP relays add a further deliverability risk, because your mail leaves from someone else's servers instead of Google's.

Every developer building an outbound email platform, a SaaS notification pipeline, or a multi-tenant cold email sender faces this decision early on. SMTP looks like the path of least resistance: it's a standard protocol supported by every programming language since the 1980s. But with strict OAuth scopes and tight sender authentication policies, it introduces real operational friction.

This guide breaks down the core technical, security, and deliverability differences between SMTP relays and the Google Gmail API to help you choose the right architecture for your sending platform.


1. Connection Architecture: Protocol vs. API

To understand why one is inherently more reliable than the other, we must look at how the connection is made under the hood.

The SMTP Handshake (Sequential & Heavy)

SMTP (Simple Mail Transfer Protocol) is a conversational protocol. To send a single email, your server must open a TCP connection to the mail server and engage in a sequential back-and-forth handshake:

Server: Connect to smtp.gmail.com:587
Gmail:  220 mx.google.com ESMTP
Server: EHLO myapp.com
Gmail:  250-mx.google.com at your service...
Server: STARTTLS
Gmail:  220 2.0.0 Ready to start TLS
Server: [Negotiates TLS] EHLO myapp.com
Gmail:  250-mx.google.com at your service...
Server: AUTH LOGIN
Gmail:  334 VXNlcm5hbWU6
Server: [Base64 Username]
Gmail:  334 UGFzc3dvcmQ6
Server: [Base64 Password]
Gmail:  235 2.7.0 Accepted
Server: MAIL FROM:<sender@company.com>
Gmail:  250 2.1.0 OK
Server: RCPT TO:<recipient@target.com>
Gmail:  250 2.1.5 OK
Server: DATA
Gmail:  354 Go ahead
Server: [Sends raw MIME content ending with <CR><LF>.<CR><LF>]
Gmail:  250 2.0.0 OK (queued as 12345)
Server: QUIT
Gmail:  221 2.0.0 closing connection

Every single step in this handshake represents network round-trips. If you are sending hundreds of personalized cold emails, this sequential state machine is slow, highly susceptible to brief packet loss, and requires complex connection pooling to prevent server timeout.

The Gmail API (Stateless & Fast)

The Gmail API is a standard RESTful HTTP/2 service. Sending an email requires a single, stateless POST request to users.messages.send with an Authorization: Bearer <token> header:

POST /gmail/v1/users/me/messages/send HTTP/2
Host: gmail.googleapis.com
Authorization: Bearer ya29.a0AfH6SMA...
Content-Type: application/json
 
{
  "raw": "RnJvbTogc2VuZGVyQGNvbXBhbnkuY29tClRvOiByZWNpcGllbnRAdGFyZ2V0LmNvbQpTdWJqZWN0OiBIZWxsbyBXb3JsZCEKClRoaXMgaXMgYSBuYXRpdmUgR21haWwgQVBJIG1lc3NhZ2Uu"
}

Because it's standard HTTP/2, your application can reuse connection pools, leverage persistent keep-alive, and complete sends in a fraction of the time. There is no conversational state, no SMTP auth negotiating, and far less room for network timeouts to corrupt the transaction. Building that raw string correctly is its own job, which we walk through in how to send email with the Gmail API in Node.js.

Diagram: SMTP needs nine sequential steps (connect, EHLO, STARTTLS, EHLO, AUTH, MAIL FROM, RCPT TO, DATA, QUIT), while the Gmail API sends with one authenticated HTTPS POST
Nine round trips versus one request.

2. Deliverability: Why the Inbox Loves APIs

Let's address the elephant in the room: Which method lands you in the Primary Inbox, and which lands you in the Spam/Promotions folder?

If you send through Gmail's own SMTP server (smtp.gmail.com) with the same account, the message also leaves Google's servers with Google's DKIM signature, so placement should be similar. The deliverability gap is with third-party SMTP relays, which many outreach platforms use to send "as" their users.

Native Authentication & SPF/DKIM Alignment

When you send through a third-party relay, the relay's servers deliver the message. If the relay's IP addresses or routing path aren't covered by your SPF record and signed with your domain's DKIM key, receiving spam filters can flag the message.

When you use the Gmail API:

  1. Google's own internal systems construct and route the email.
  2. The email is signed by Google's native DKIM keys (d=gmail.com or your Workspace DKIM key d=yourdomain.com).
  3. The email originates from Google's high-reputation, primary IP ranges.

An email sent through the Gmail API leaves the same infrastructure as one sent by clicking "Send" in Gmail, so there is no outside relay for filters to weigh. That doesn't make content or sending patterns irrelevant: Google's sender guidelines still apply, including keeping the spam rate below 0.3%.

Why SPF/DKIM/DMARC Checks are Mandatory

Even with the Gmail API, your custom Workspace domain must have perfect DNS records. If your domain's SPF record is missing include:_spf.google.com, Gmail API sends will still struggle to align under strict DMARC rules.

The "Alias" Handling Nightmare

If your outreach platform allows users to send from an email alias (e.g. sending as sales@company.com from a logged-in user@company.com account), SMTP handles this poorly. SMTP clients must authenticate as the primary account but rewrite the From: header. Many mail servers treat this discrepancy as a spoofing attempt and route the email to Spam.

The Gmail API handles aliases natively. As long as the alias is registered in the user's Gmail settings, the API aligns the envelopes, signs them correctly, and ensures deliverability stays high.


3. Security: OAuth2 vs. Plaintext Credentials

From an engineering and security perspective, SMTP is a massive liability, especially in multi-tenant SaaS applications where users connect their accounts.

FeatureSMTP RelaysGmail API (OAuth2)
Credential TypeUsername + App Password, or a full-mailbox OAuth tokenOpaque, revocable Access/Refresh tokens
RevocationMust log in to Google Account, change password, or delete App PasswordOne-click disconnect (invalidates refresh token instantly)
Permissions ScopeAll-or-Nothing. A password, or OAuth with the full https://mail.google.com/ scopeGranular. Restricted to gmail.send (cannot read or delete mail)
Data EncryptionCredentials saved in database (requires high-risk encryption)Tokens encrypted with AES-256-GCM (industry standard)

Google Workspace accounts stopped accepting passwords over SMTP on March 14, 2025, and third-party apps now have to use OAuth (Google). SMTP can use OAuth too, but only with the https://mail.google.com/ scope, which grants full access to the mailbox (Google's XOAUTH2 docs). If you ask users for an App Password instead, you are asking them to trust you with their entire account. Furthermore, storing these App Passwords in your database creates a single point of failure: if your database is breached, the attacker gains the ability to log in and send emails from every single user's account.

By contrast, the Gmail API uses OAuth2. Users authorize your app via Google's secure consent screen. You only request the https://www.googleapis.com/auth/gmail.send scope (why we chose send-only).

Why Scopes Matter for Trust

By requesting ONLY gmail.send, you explicitly prove to your users that your application cannot read their inbox, cannot view their chats, and cannot delete their emails. This granular trust is crucial for user adoption.


4. Quotas and Throttling: Safe Throttling is a Feature

A common complaint about the Gmail API is its strict sending limits (we break down every Gmail sending limit separately):

  • Free Gmail Accounts (@gmail.com): 500 emails/day
  • Google Workspace Accounts: 2,000 emails/day

Developers often compare this to transactional services like SendGrid or Mailgun, which allow you to send millions of emails daily.

However, for outbound cold email, sending millions of emails from a single domain is a quick way to permanently ruin your domain's reputation. To keep your emails out of the spam folder, your sending behavior must mimic human activity.

Instead of fighting the limits, modern outreach platforms treat them as built-in deliverability guardrails.

How to Architect a Throttled Send Queue

To successfully send via the Gmail API without triggering Google's concurrent rate limit errors (429 rateLimitExceeded), you should implement an asynchronous queue. Here is a simplified architecture diagram of how we do this:

graph TD
  A[User Triggers Campaign] --> B[Write One Row per Recipient to Postgres]
  B --> C[Enqueue One Message per Recipient to Cloudflare Queues]
  C --> D[Queue Worker Claims the Row: PENDING to SENDING]
  D --> E{Daily Quota Check}
  E -- Exceeded --> F[Defer Until the Quota Resets, with Jitter]
  E -- Safe --> G[Fetch Decrypted OAuth Token]
  G --> H[Call gmail.users.messages.send]
  H --> I[Mark Sent & Record Signed Tracking Tokens]

For a full working example, see how to send email with the Gmail API in Node.js. If you're adding tracking to an app, email tracking for web applications covers the architecture.

To handle rate limits and quota errors gracefully, your worker process should use an exponential backoff with jitter strategy when encountering transient errors. Here is a TypeScript example of this logic:

import { google } from 'googleapis';
 
async function sendEmailWithRetry(
  auth: any,
  rawMime: string,
  attempt: number = 0,
  maxAttempts: number = 6
): Promise<any> {
  const gmail = google.gmail({ version: 'v1', auth });
  
  try {
    const response = await gmail.users.messages.send({
      userId: 'me',
      requestBody: {
        raw: rawMime,
      },
    });
    return response.data;
  } catch (error: any) {
    const status = error.status || error.code;
    
    // Retry on 429 (Rate Limit) or 5xx (Transient Server Error)
    if ((status === 429 || status >= 500) && attempt < maxAttempts) {
      // Calculate exponential delay: 2^attempt * 1000ms + random jitter
      const baseDelay = Math.pow(2, attempt) * 1000;
      const jitter = Math.random() * 1000;
      const delay = baseDelay + jitter;
      
      console.warn(`Transient error ${status}. Retrying in ${delay.toFixed(0)}ms...`);
      await new Promise((resolve) => setTimeout(resolve, delay));
      return sendEmailWithRetry(auth, rawMime, attempt + 1, maxAttempts);
    }
    
    // Terminal error, throw immediately
    throw error;
  }
}

5. Summary: Which Should You Choose?

Choose SMTP if:

  • You are building a legacy, internal-only script where security is not a concern and App Passwords are easy to hardcode.
  • You are connecting to a wide variety of non-Google email providers (such as Outlook, Yahoo, or custom SMTP servers) and need a single, generic protocol to handle them all.

Choose the Gmail API if:

  • Security & trust are paramount: You are building a multi-tenant platform where users must securely authorize access without exposing plaintext passwords.
  • Deliverability is your primary metric: You want outreach emails to leave from Google's own servers with Google's DKIM signature, instead of a third-party relay.
  • You want structured errors: The API returns HTTP status codes and error reasons (quota exceeded, invalid credentials, malformed message) that a send queue can retry or surface. Note that push notifications for new mail, such as replies, need a read-level scope, so a send-only app doesn't get them.

At Maildriply, we chose the Gmail API-First approach. We skip SMTP entirely, so every email leaves your own Gmail account through the API with only the gmail.send scope.

Connect your Gmail account to Maildriply to send and track email that way.

Explore Maildriply

Keep reading