All Articles
Email & Deliverability

Why a Gmail App Password Isn't a Real Email Solution (Even Though It 'Works')

Shahid MalikBy Shahid MalikSeptember 4, 20266 min read

I wired up Django's email backend to send transactional email through a Gmail App Password on Tabeer.ai. It reported success on every send. Two of those emails still silently bounced days later — here's why, and what actually fixes it.

On Tabeer.ai I needed transactional email fast — account verification, password resets, weekly progress digests — and the quickest path was a Gmail App Password against Django's SMTP backend. It's a genuinely common shortcut for a project that isn't ready to pay for a transactional email provider yet. It also has a failure mode that doesn't show up until it's already cost you real users, and that's the part worth writing down.

The Setup (This Part Really Is Five Minutes)

EMAIL_BACKEND = "django.core.mail.backends.smtp.EmailBackend"
EMAIL_HOST = "smtp.gmail.com"
EMAIL_PORT = 587
EMAIL_HOST_USER = "info.tabeerai@gmail.com"
EMAIL_HOST_PASSWORD = "xxxx xxxx xxxx xxxx"  # Gmail App Password, not the account password
EMAIL_USE_TLS = True
DEFAULT_FROM_EMAIL = "Tabeer.ai <info.tabeerai@gmail.com>"

One detail that trips people up: DEFAULT_FROM_EMAIL has to match the authenticated Gmail account (or a verified alias on it). Gmail's relay will reject — or silently rewrite — a From address it doesn't recognize as belonging to the authenticating account. I initially wanted hello@tabeer.ai in that field; it doesn't work through a personal Gmail relay, only through the actual @gmail.com address or a properly configured "Send As" alias.

With that config, send_mail() returns 1 and raises nothing. Every test — locally, then on the production server — looked like a clean pass.

Where It Actually Fails

Days later, a bounce notification came back for a verification email:

550 5.7.30 ... DKIM authentication didn't pass ...
Gmail requires all email bulk senders to authenticate their email with DKIM

Not a one-off — a second bounce, for a different message, came in later the same way. This is the actual failure mode: SMTP-level success only confirms Gmail accepted the message for relay, not that it delivered. Gmail evaluates deliverability asynchronously, after your code has already moved on and logged success. A plain consumer @gmail.com account has no DKIM record you control — Google signs outbound mail with its own infrastructure key, which satisfies casual, low-volume personal email but fails Gmail's own bulk-sender authentication policy the moment your app starts sending anything at automation volume (verification emails, password resets, digests — exactly the transactional pattern most apps need).

This is the trap: your own test suite cannot catch this. send_mail() succeeding is not proof of delivery. If your only signal is "did the function raise," you will ship this and find out from a support ticket, not a test failure.

What Actually Fixes It

Two real options, both requiring domain-level authentication Gmail's consumer relay structurally can't give you:

  1. A transactional email provider (SendGrid, Postmark, Resend, AWS SES) with your own domain's SPF, DKIM, and DMARC DNS records configured. This is the standard fix, and most of these have generous free tiers for the volume a small app actually sends.
  2. Google Workspace, if you specifically want to keep sending "from" a Gmail-family address — a Workspace mailbox on your own domain lets you configure real DKIM signing for that domain, unlike a free consumer Gmail account.

If you're already on Cloudflare for DNS (I am, for this project), adding the SPF/DKIM/DMARC records for either option is a few TXT record API calls — the actual blocker is almost never the DNS, it's picking a provider and generating the DKIM keypair it gives you.

The Actual Lesson

"It sent without an error" and "it was delivered" are different claims, and for any provider with a serious bulk-sender policy — Gmail very much included — you cannot verify the second one synchronously. If transactional email matters for your product (and account verification usually blocks a user from ever activating), don't let a green checkmark from send_mail() be the only thing you check. Watch for bounce webhooks, or better, don't route production transactional volume through a personal Gmail account in the first place — it's fine for a prototype, and a real liability past that.

If you're debugging email deliverability on a Django or Nuxt project, or setting up SPF/DKIM/DMARC properly the first time, get in touch.

Related Topics:EmailDjangoSMTPDKIM

Related Articles

Security

Rate Limiting, Token Blacklisting, and Admin MFA — Auth Hardening for Tabeer.ai

Part two of the production-readiness checklist: authentication and account security. Five of fifteen items were genuinely missing — rate limiting, real logout, admin MFA, consent records, and self-service data export/deletion — and here's exactly how each got fixed without a new dependency for most of them.

10 min read
Security

The Encryption Checklist for a Small Django Production Stack

Thirteen encryption checks, framed as 'encryption at multiple layers, not just HTTPS.' Most of the layers already existed — TLS to Postgres, client-side-encrypted backups — one item doesn't apply to this architecture at all, and two needed an AWS console check I couldn't run myself.

7 min read
Monitoring & Observability

Flower + Celery on Django: How I Found Silently Failing Tasks on Tabeer.ai

Users weren't getting some transactional emails. The mail-sending code looked fine, the logs weren't obviously screaming — the actual answer was Celery tasks failing with zero visibility into it. Here's the practical setup: systemd unit, basic auth, nginx subdomain, real commands.

7 min read
Shahid Malik - AI-First Odoo Consultant

Shahid Malik

AI-First Odoo ERP Specialist

Shahid Malik is an AI-first Odoo consultant helping businesses solve complex ERP and business process challenges. His work combines Odoo consulting, process optimization, automation, integrations, migrations, and practical AI solutions to build scalable and reliable business systems.

Book a consultation for your Odoo project
Discuss Your Odoo Project