16
votes

I'm trying to send an email from a Google account using Python's smtplib, but getting an error, and now I'm kind of at a loss. Google responds with the following: Please log in via your web browser and then try again. Learn more at https://support.google.com/mail/answer/78754.

The account has two factor authentication enabled, so I'm using an app specific password for my login. To my understanding, this should then work without enabling the setting for less secure apps, shouldn't it? I've been doing the same with another account while testing without a problem, but now I finally got the credentials for the proper account and there it won't accept the authentication.

I'm aware that there is a Python Gmail API thingy to use with OAuth, but if at all possible I don't want to include more packages and rewrite much, and I don't really want to enable the "less secure apps" setting either. Is there a way to get this working without either?

If it makes a difference, here is the code I use for sending email. As said before, this was working fine with another account, so I'm not sure if it's actually relevant.

def send_mail(to_address, subject, body):
    smtp_user = "[email protected]"
    smtp_password = "MyAppPasswordFromGoogle"
    server = "smtp.gmail.com"
    port = 587

    msg = MIMEMultipart("alternative")
    msg["Subject"] = subject
    msg["From"] = smtp_user
    msg["To"] = to_address
    msg.attach(MIMEText(body, "html"))
    s = smtplib.SMTP(server, port)
    s.connect(server, port)
    s.ehlo()
    s.starttls()
    s.ehlo()
    s.login(smtp_user, smtp_password)
    s.sendmail(smtp_user, to_address, msg.as_string())
    s.quit()

Edit: There is an interesting difference between the two accounts: on https://myaccount.google.com/lesssecureapps, my old (working) one says "this setting isn't available for accounts that have two factor authentication enabled", while the new one says "this setting is managed by your domain administrator", even though both use 2FA and it's also forced in both domains. So I suppose there is some setting that the domain admin has to change, but I don't know which one that would be.

4

4 Answers

5
votes

Seems simple, but check to make sure Allow less secure apps is enabled.

5
votes

I tried to replicate exactly your case (with an account that has a two factor authentication enabled). After creating my app password, I used it in the code.

Anyway, I think your problem is the following:

s = smtplib.SMTP(server, port)
s.connect(server, port)

You execute the connection twice.

Try with

s = smtplib.SMTP()
s.connect(server, port)

or just this

s = smtplib.SMTP(server, port)

The entire code:

import smtplib
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText


smtp_user = '[email protected]'
smtp_password = 'my16charactersAppPassword'
server = 'smtp.gmail.com'
port = 587
msg = MIMEMultipart("alternative")
msg["Subject"] = 'Why,Oh why!'
msg["From"] = smtp_user
msg["To"] = "[email protected]"
msg.attach(MIMEText('\nsent via python', 'plain'))
s = smtplib.SMTP(server, port)
s.ehlo()
s.starttls()
s.login(smtp_user, smtp_password)
s.sendmail(smtp_user, "[email protected]", msg.as_string())
s.quit()
0
votes

I am just curious if you have enabled IMAP (despite of the fact that SMTP has nothing to do with IMAP)...

Here is an old list with many different solutions - Sending email through Gmail SMTP server with C#

0
votes

As of now, google will remove the "Allow unsecure apps options" as suggested by other answers till May 30, 2022. Now you would need to generate specific app passwords.

  1. Go to Google Accounts Page
  2. Turn on the 2-step verification.
  3. Security > App passwords enter image description here
  1. Select "Other apps" from the app menu.

This gives you app password. You could use the same email and this password to login with your python script