32

I have a small problem with sending an email in Python:

#me == my email address
#you == recipient's email address
me = "some.email@gmail.com"
you = "some_email2@gmail.com"

# Create message container - the correct MIME type is multipart/alternative.
msg = MIMEMultipart('alternative')
msg['Subject'] = "Alert"
msg['From'] = me
msg['To'] = you

# Create the body of the message (a plain-text and an HTML version).
html = '<html><body><p>Hi, I have the following alerts for you!</p></body></html>'

# Record the MIME types of both parts - text/plain and text/html.
part2 = MIMEText(html, 'html')

# Attach parts into message container.
# According to RFC 2046, the last part of a multipart message, in this case
# the HTML message, is best and preferred.
msg.attach(part2)

# Send the message via local SMTP server.
s = smtplib.SMTP('aspmx.l.google.com')
# sendmail function takes 3 arguments: sender's address, recipient's address
# and message to send - here it is sent as one string.
s.sendmail(me, you, msg.as_string())
s.quit()

So before now, my program didn't give me an error, but it also didn't send me an email. And now python gives me an error:

SMTPServerDisconnected: Connection unexpectedly closed

How can I fix this?

Michael
  • 15,386
  • 36
  • 94
  • 143
  • 1
    did u check ur internet connection ? – Anurag-Sharma Jul 20 '13 at 07:37
  • 3
    hey see this question : - http://stackoverflow.com/questions/6270782/sending-email-with-python – Anurag-Sharma Jul 20 '13 at 07:39
  • possible duplicate of [Issue with sending mails from a distribution mail id \[Python\]](http://stackoverflow.com/questions/9972216/issue-with-sending-mails-from-a-distribution-mail-id-python) – tripleee Jul 20 '13 at 07:41
  • i think the problem is in local SMTP server – Michael Jul 20 '13 at 08:51
  • do anyone know any other public SMTP servers? – Michael Jul 20 '13 at 08:51
  • smtp.gmail.com on 465 or 587? just ensure to allow -in thes ender account- "access to less secure applications" (in the Security settings for the sender account). perhaps THAT server is not working as expected, but other google servers are working – Luis Masuelli Oct 08 '14 at 22:45

7 Answers7

27

TLDR: switch to authenticated connection over TLS.

Most probably the gmail server rejected the connection after the data command (very nasty of them to do so at this stage :). The actual message is most probably this one:

    retcode (421); Msg: 4.7.0 [ip.octets.listed.here      15] Our system has detected an unusual rate of
    4.7.0 unsolicited mail originating from your IP address. To protect our
    4.7.0 users from spam, mail sent from your IP address has been temporarily
    4.7.0 rate limited. Please visit
    4.7.0  https://support.google.com/mail/answer/81126 to review our Bulk Email
    4.7.0 Senders Guidelines. qa9si9093954wjc.138 - gsmtp

How do I know that? Because I've tried it :) with the s.set_debuglevel(1), which prints the SMTP conversation and you can see firsthand what's the issue.

You've got two options here:

  1. Continue using that relay; as explained by Google, it's unencrypted gmail-to-gmail only, and you have to un-blacklist your ip through their procedure

  2. The most fool-proof option is to switch to TLS with authentication

Here's how the changed source looks like:

# skipped your comments for readability
import smtplib
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText

me = "some.email@gmail.com"
my_password = r"your_actual_password"
you = "some.email2@gmail.com"

msg = MIMEMultipart('alternative')
msg['Subject'] = "Alert"
msg['From'] = me
msg['To'] = you

html = '<html><body><p>Hi, I have the following alerts for you!</p></body></html>'
part2 = MIMEText(html, 'html')

msg.attach(part2)

# Send the message via gmail's regular server, over SSL - passwords are being sent, afterall
s = smtplib.SMTP_SSL('smtp.gmail.com')
# uncomment if interested in the actual smtp conversation
# s.set_debuglevel(1)
# do the smtp auth; sends ehlo if it hasn't been sent already
s.login(me, my_password)

s.sendmail(me, you, msg.as_string())
s.quit()

Now, if try to 'cheat' the system and send with a different (non-gmail) address it's gonna a) require you to connect to a different hostname (some of the MX records for gmail), then b) stop you and close the connection on the grounds of blacklisted ip, and c) do reverse DNS, DKIM and lots of other countermeasures to make sure you're actually in control of the domain you presented in the MAIL FROM: address.

Finally, there's also option 3) - use any other email relaying service, there are tons of good ones :)

Todor Minakov
  • 19,097
  • 3
  • 55
  • 60
17

I Had the same issue and solved it just by specifying the right port like this:

smtplib.SMTP('smtp.gmail.com', 587)
Tiwtiw
  • 465
  • 4
  • 10
8

Using smtplib.SMTP_SSL() instead of smtplib.SMTP() works for me. Try this.

Nurul Akter Towhid
  • 3,046
  • 2
  • 33
  • 35
1

I have realised a strange behavior. I have used similar codes mentioned both the question and answers. My code has been working for the last days. However, today I encountered the error message mentioned in the question.

My solution: I had tried my successful attempt via library network. Today I have tried it via Starbucks network (over captive portal). I changed it to my mobile network. It started working again.

Possibly, Google rejects requests from unreliable networks.

Onur Tuna
  • 1,030
  • 1
  • 10
  • 28
0

I was facing the same problem. In my case, password was changed just few days back. So, it was giving the error. As I updated the password in code, its working like a charm...!!!

Sohel Pathan
  • 367
  • 3
  • 13
0

Googlers: I had a test smtp server running locally. I was getting this error because I was shutting down the local smtp server before closing the client smtp.

Daniel Butler
  • 3,239
  • 2
  • 24
  • 37
  • Do you think that is what the problem was in the question, or are you adding this only because it had the same error message. If it was just because the error message was the same it would be better to add a new question and provide this as an answer to that new question. – Jason Aller Jul 30 '20 at 15:36
  • Why not ask the same question for all of the answers above? – Daniel Butler Jul 30 '20 at 15:42
  • Because the review queue only shows one answer for review at a time. It may be fair to ask the same of the others, and you can flag them for review if you wish. – Jason Aller Jul 30 '20 at 15:44
  • That makes sense. I think it could be an answer to the question above, none have been accepted. I view the answers section as help for future users with the same error message not only the person asking the question especially when an answer has not been accepted. – Daniel Butler Jul 30 '20 at 15:48
  • The benefit of wording a new question is that it is more likely to be found if someone searches for the error message and a few keywords. The problem with a question that is basically an error message is that if the error message is generic then you can end up with tons of unrelated answers below it which all might be great answers to a more specific question. – Jason Aller Jul 30 '20 at 15:53
0
with smtplib.SMTP_SSL("smtp.mail.yahoo.com", port=465) as connection:

connection.login(
    user=my_email,
    password=my_password
)

connection.sendmail(
    from_addr=my_email,
    to_addrs=friend_address,
    msg=f"Subject:Text\n\n"
        f"Body of the text"
)

This is my code. I hope it will be helpful.