1
0 Comments

gmail cut me off mid-send 3 times before i figured out SMTP connection management for cold outreach

i have been sending cold outreach emails to marketing agencies via gmail SMTP. 25 at a time, 2.5 minute delay between each. the pipeline kept crashing on email #24 or #25 and i lost hours of data before i figured out what was happening.

the problem

gmail SMTP connections have a timeout. if you hold a connection open for ~60 minutes (which is what happens when you send 25 emails with 150 second delays), the connection silently expires. your next send attempt gets a 421 error: "Connection expired, try reconnecting."

that part is annoying but manageable. the real problem was what happened next.

the data loss bug

my script was structured like every tutorial says:

  1. connect to SMTP
  2. send emails in a loop
  3. quit SMTP
  4. save the sent log

when the connection expired on email #24, the send failed and broke out of the loop. then smtp.quit() tried to send a QUIT command on a dead connection and threw SMTPServerDisconnected. the save step never ran.

result: 24 emails successfully delivered to real agencies, but my sent log had no record of them. next time the script ran, it tried to send to those same agencies again. some got duplicate pitches.

the fix (obvious in hindsight)

move the save BEFORE the quit. wrap quit in try/except.

the save is the important part. the quit is just being polite to the SMTP server. if the connection is dead, the server already knows.

what i actually learned

  1. never put your most important operation (saving state) after a network call that can fail (smtp.quit). save first, clean up second.

  2. gmail enforces connection timeouts around 60 minutes. if your batch takes longer than that, you need to reconnect mid-batch or accept the last email will fail.

  3. dedup your email lists across batch files. i had the same email appearing in 3 different batch files because i scraped the same agency from different search results. one agency got 3 identical pitches.

  4. python output buffering hides your progress. use python3 -u (unbuffered) when running long scripts so you can see output in real-time.

  5. always test your save logic separately from your send logic. i tested "does it send?" and "does it save?" but never tested "does it save when the send partially fails?" that was the gap.

the whole episode cost me about 2 hours of debugging and some duplicate emails. not catastrophic, but the kind of bug that erodes trust if you are pitching a professional outreach service.

anyone else hit connection timeout issues with gmail SMTP? curious if there is a cleaner pattern than what i ended up with.

on March 30, 2026