---
title: Why Gmail SMTP fails in production
metaTitle: Why Gmail SMTP fails in production, and what to use
description: Gmail SMTP works on your laptop and breaks under real load. App passwords, daily limits, spoofed From addresses, and DMARC alignment, explained with the fix.
date: 2026-05-29
author: emails.sh
tags: Deliverability
---

Pointing your app at `smtp.gmail.com` is the fastest way to get email working, and the fastest way to acquire a production incident. It fails in at least four independent ways, and each one produces a different symptom, which is why people fix one and think they are done.

## Your password stopped working

Google withdrew basic authentication for SMTP. A regular account password no longer authenticates, so the failure looks like this:

```text
535-5.7.8 Username and Password not accepted.
```

The workaround is an app password, which requires two-step verification on the account. It is a sixteen character credential scoped to one application, which is better than your account password but still a long-lived secret sitting in an environment variable, tied to a human's personal account, and revoked the day that person leaves or Google prompts a security review.

Workspace administrators can also disable app passwords for the whole domain, at which point your production sending stops with no code change on your side.

## The daily limit is a person's limit

Gmail's SMTP relay is metered for a human sending mail, not an application sending notifications. Free Gmail accounts have a substantially lower ceiling than Workspace accounts, and the exact figures move, so check Google's current sending limits documentation rather than trusting a number in a tutorial.

What matters is the shape: the limit is per day, it counts recipients rather than messages, and hitting it does not fail loudly at first. You get a temporary block, sends start deferring, and the account may be restricted for a period. A single launch email to a few hundred users will find it.

You also cannot send to a large `bcc` list to get around it, because recipients are what is counted.

## Your From address is being rewritten

This is the failure nobody predicts. Gmail will not let you send as an arbitrary address. Set `from: 'noreply@acme.com'` while authenticating as `you@gmail.com` and one of two things happens: the header is rewritten to the authenticated account, or the message is sent with a mismatch that receivers treat as spoofing.

Even after you add the address as a verified alias, the DMARC problem remains. Gmail signs with `gmail.com`, your From says `acme.com`, and the DKIM signature does not align with the visible From domain. DMARC fails, and if you publish `p=quarantine` or `p=reject` you are asking receivers to bin your own mail. This is the alignment concept explained in [SPF, DKIM, and DMARC explained for developers](/blog/spf-dkim-dmarc-explained).

The result is a message that is technically delivered and practically invisible, sitting in a spam folder your users never open.

## Serverless makes it worse

If the code sending through Gmail runs in a serverless function, add the transport problems on top: outbound SMTP ports are commonly blocked, the handshake plus a cold start can exhaust the execution budget, and there is no persistent connection to reuse. Those are covered in [why nodemailer does not work on Vercel](/blog/nodemailer-vercel).

## What each symptom actually means

| Symptom | Cause | Fix |
| --- | --- | --- |
| `535-5.7.8` on auth | Basic auth withdrawn | App password, or move off Gmail |
| Sends work then stop for hours | Daily recipient limit reached | Move off Gmail |
| From address appears as your Gmail | Gmail rewrote an unverified sender | Move off Gmail |
| Delivered but always in spam | DKIM signed by gmail.com, not aligned | Move off Gmail |
| Connection times out in production only | Serverless, port blocked or budget exceeded | Send over HTTPS |
| `550-5.7.1` on a bulk send | Treated as unsolicited bulk mail | Move off Gmail |

Four of six rows say the same thing, which is the point. Gmail SMTP is a personal mail transport being used as an application transport.

## What to do instead

Send over an HTTPS API from a domain you control and can sign with your own DKIM. One request, no ports, no personal account in the loop, and a DKIM signature that aligns with your From address.

```bash
curl -X POST https://emails.sh/v1/emails \
  -H "Authorization: Bearer $EMAILSSH_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "from": "Acme <noreply@acme.com>",
    "to": ["someone@example.com"],
    "subject": "Reset your password",
    "html": "<p>Choose a new password using the link below.</p>",
    "text": "Choose a new password using the link below.",
    "reply_to": "support@acme.com"
  }'
```

```py
import os, requests

requests.post(
    "https://emails.sh/v1/emails",
    headers={"Authorization": f"Bearer {os.environ['EMAILSSH_API_KEY']}"},
    json={
        "from": "Acme <noreply@acme.com>",
        "to": ["someone@example.com"],
        "subject": "Reset your password",
        "html": "<p>Choose a new password using the link below.</p>",
        "text": "Choose a new password using the link below.",
    },
    timeout=10,
).raise_for_status()
```

Set `reply_to` to an address a human reads. `noreply@` as a From address is fine; as the only route back to you it is hostile.

## When Gmail SMTP is genuinely fine

It is not always wrong. A cron job on a server you own that mails you and two colleagues once a day is exactly what the relay is for. The line is whether the recipients are people you know or people who signed up. As soon as strangers receive it, you need your own authenticated domain.

## Check what receivers see

The fastest confirmation that you have fixed it is the header block on a delivered message.

```text
Authentication-Results: mx.example.com;
  dkim=pass header.d=acme.com;
  dmarc=pass header.from=acme.com
```

`header.d` matching your own domain is the line that matters. Paste a full header block into the [email header analyzer](/tools/email-header-analyzer) if you want it read out, or run a message through the [mail tester](/tools/mail-tester).

## Questions

### Can I use Gmail SMTP for a production app?

Only if the recipients are you and a handful of colleagues. For user-facing mail the daily recipient limit, the From rewriting, and the DKIM alignment failure make it unsuitable regardless of how you authenticate.

### Does a Google Workspace account fix the limits?

It raises them, but the ceiling is still a per-user daily figure meant for a person. The alignment problem also remains unless you send from a domain you sign yourself.

### Why do my Gmail-sent emails go to spam?

Most often because the DKIM signature belongs to gmail.com while the From header shows your domain, so DMARC does not pass alignment. Receivers treat unaligned mail claiming to be from your brand as suspicious.

### What is the minimum change to fix this?

Verify your domain with a sending provider, publish the DKIM entries they give you, and swap the SMTP call for an HTTPS POST. The code change is one function; the DNS change is a single visit to your registrar.

## Related

- [Why nodemailer does not work on Vercel](/blog/nodemailer-vercel)
- [SPF, DKIM, and DMARC explained for developers](/blog/spf-dkim-dmarc-explained)
- [Why your password reset email goes to spam](/blog/password-reset-email-spam)
- [How to send email from Cursor](/blog/send-email-from-cursor)
