How to Fix Google SMTP Error 454 4.7.0: Too Many Login Attempts in Scripted Email Sending


30 views

When automating email delivery through Google's SMTP servers (smtp.gmail.com on port 587 or 465), many developers encounter the frustrating 454 error:

SMTP Error: 454 4.7.0 Too many login attempts, please try again later

Google imposes strict rate limits on SMTP authentication attempts to prevent abuse. The thresholds aren't publicly documented, but empirical testing shows:

  • Approximately 100-150 emails per hour triggers the block
  • Simultaneous connections from the same IP accelerate rate limiting
  • New accounts have tighter restrictions than established ones

Here's a Python example that demonstrates proper SMTP connection handling with rate limiting:

import smtplib
import time
from email.mime.text import MIMEText

MAX_EMAILS_PER_HOUR = 100
DELAY_BETWEEN_EMAILS = 36  # seconds (100 emails/hour = ~36s between sends)

def send_email(subject, body, to_email):
    msg = MIMEText(body)
    msg['Subject'] = subject
    msg['From'] = 'your@gmail.com'
    msg['To'] = to_email
    
    try:
        with smtplib.SMTP('smtp.gmail.com', 587) as server:
            server.starttls()
            server.login('your@gmail.com', 'your_app_password')
            server.send_message(msg)
            time.sleep(DELAY_BETWEEN_EMAILS)
    except smtplib.SMTPException as e:
        print(f"SMTP error occurred: {str(e)}")
        if '454 4.7.0' in str(e):
            print("Rate limited - waiting 1 hour")
            time.sleep(3600)

For serious email delivery needs, consider these approaches:

# Using connection pooling (Python example)
class SMTPConnectionPool:
    def __init__(self, max_connections=3):
        self.pool = []
        self.max_connections = max_connections
    
    def get_connection(self):
        if not self.pool or len(self.pool) < self.max_connections:
            server = smtplib.SMTP('smtp.gmail.com', 587)
            server.starttls()
            server.login('your@gmail.com', 'your_app_password')
            self.pool.append(server)
            return server
        return random.choice(self.pool)
  • Use Google's Gmail API instead of SMTP (higher quota)
  • Implement exponential backoff when errors occur
  • Distribute sending across multiple Google accounts
  • Consider professional SMTP services (SendGrid, Mailgun, etc.)

Always use App Passwords instead of your main Google account password when scripting SMTP access. Enable 2-Step Verification first, then generate app-specific passwords under your Google Account security settings.


When working with Google's SMTP servers (smtp.gmail.com on port 587 or 465), developers often encounter the frustrating 454 error. This occurs when your application makes too many authentication attempts in a short period, triggering Google's security mechanisms to prevent potential brute-force attacks.

Google imposes these restrictions to:

  • Prevent account compromise through brute-force attacks
  • Limit spam sent through compromised accounts
  • Maintain server stability under heavy loads

Here are several approaches to handle this in your code:

1. Implement Exponential Backoff

Add delay between attempts that grows exponentially:


import time
import smtplib

def send_email_with_backoff():
    max_retries = 5
    base_delay = 5  # seconds
    
    for attempt in range(max_retries):
        try:
            server = smtplib.SMTP('smtp.gmail.com', 587)
            server.starttls()
            server.login('your_email@gmail.com', 'your_password')
            # ... send email ...
            break
        except smtplib.SMTPException as e:
            if '454' in str(e):
                wait_time = base_delay * (2 ** attempt)
                print(f"Attempt {attempt + 1}: Waiting {wait_time} seconds")
                time.sleep(wait_time)
            else:
                raise

2. Use OAuth 2.0 Instead of Password

Google recommends using OAuth for higher limits:


from google.oauth2 import service_account
import google.auth.transport.requests
from email.message import EmailMessage
import smtplib

credentials = service_account.Credentials.from_service_account_file(
    'service-account.json',
    scopes=['https://www.googleapis.com/auth/gmail.send']
)

message = EmailMessage()
message['From'] = 'service-account@your-domain.iam.gserviceaccount.com'
message['To'] = 'recipient@example.com'
message['Subject'] = 'Test email'
message.set_content('This is a test email')

with smtplib.SMTP('smtp.gmail.com', 587) as smtp:
    smtp.starttls()
    smtp.login(credentials.signer_email, credentials.token)
    smtp.send_message(message)

3. Queue System with Rate Limiting

For bulk sending, implement a queue with controlled throughput:


from queue import Queue
import threading
import time

email_queue = Queue()
MAX_EMAILS_PER_HOUR = 100  # Stay under Google's limits

def email_worker():
    while True:
        email_data = email_queue.get()
        try:
            send_email(email_data)
        finally:
            time.sleep(3600 / MAX_EMAILS_PER_HOUR)  # Spread emails evenly
            email_queue.task_done()

def send_email(data):
    # Your email sending implementation
    pass

# Start worker threads
for i in range(3):  # 3 concurrent senders
    threading.Thread(target=email_worker, daemon=True).start()

# Add emails to queue
for email in email_list:
    email_queue.put(email)

email_queue.join()

For mission-critical applications:

  • Use multiple SMTP accounts with round-robin distribution
  • Consider commercial email services like SendGrid or Mailgun
  • Implement proper error logging and alerting for rate limits

Set up monitoring for 454 errors:


import logging
from prometheus_client import Counter

smtp_454_errors = Counter('smtp_454_errors', 'Count of SMTP 454 errors')

try:
    # SMTP operation
except smtplib.SMTPException as e:
    if '454' in str(e):
        smtp_454_errors.inc()
        logging.warning('SMTP rate limit hit: %s', e)