25

Here's my script:

#!/usr/bin/python

import smtplib
msg = 'Hello world.'

server = smtplib.SMTP('smtp.gmail.com',587) #port 465 or 587
server.ehlo()
server.starttls()
server.ehlo()
server.login('myname@gmail.com','mypass')
server.sendmail('myname@gmail.com','somename@somewhere.com',msg)
server.close()

I'm just trying to send an email from my gmail account. The script uses starttls because of gmail's requirement. I've tried this on two web hosts, 1and1 and webfaction. 1and1 gives me a 'connection refused' error and webfaction reports no error but just doesn't send the email. I can't see anything wrong with the script, so I'm thinking it might be related to the web hosts. Any thoughts and comments would be much appreciated.

EDIT: I turned on debug mode. From the output, it looks like it sent the message successfully...I just never receive it.

send: 'ehlo web65.webfaction.com\r\n'
reply: '250-mx.google.com at your service, [174.133.21.84]\r\n'
reply: '250-SIZE 35651584\r\n'
reply: '250-8BITMIME\r\n'
reply: '250-STARTTLS\r\n'
reply: '250-ENHANCEDSTATUSCODES\r\n'
reply: '250 PIPELINING\r\n'
reply: retcode (250); Msg: mx.google.com at your service, [174.133.21.84]
SIZE 35651584
8BITMIME
STARTTLS
ENHANCEDSTATUSCODES
PIPELINING
send: 'STARTTLS\r\n'
reply: '220 2.0.0 Ready to start TLS\r\n'
reply: retcode (220); Msg: 2.0.0 Ready to start TLS
send: 'ehlo web65.webfaction.com\r\n'
reply: '250-mx.google.com at your service, [174.133.21.84]\r\n'
reply: '250-SIZE 35651584\r\n'
reply: '250-8BITMIME\r\n'
reply: '250-AUTH LOGIN PLAIN\r\n'
reply: '250-ENHANCEDSTATUSCODES\r\n'
reply: '250 PIPELINING\r\n'
reply: retcode (250); Msg: mx.google.com at your service, [174.133.21.84]
SIZE 35651584
8BITMIME
AUTH LOGIN PLAIN
ENHANCEDSTATUSCODES
PIPELINING
send: 'AUTH PLAIN *****\r\n'
reply: '235 2.7.0 Accepted\r\n'
reply: retcode (235); Msg: 2.7.0 Accepted
send: 'mail FROM:<myname@gmail.com> size=12\r\n'
reply: '250 2.1.0 OK 4sm652580yxq.48\r\n'
reply: retcode (250); Msg: 2.1.0 OK 4sm652580yxq.48
send: 'rcpt TO:<myname@gmail.com>\r\n'
reply: '250 2.1.5 OK 4sm652580yxq.48\r\n'
reply: retcode (250); Msg: 2.1.5 OK 4sm652580yxq.48
send: 'data\r\n'
reply: '354  Go ahead 4sm652580yxq.48\r\n'
reply: retcode (354); Msg: Go ahead 4sm652580yxq.48
data: (354, 'Go ahead 4sm652580yxq.48')
send: 'Hello world.\r\n.\r\n'
reply: '250 2.0.0 OK 1240421143 4sm652580yxq.48\r\n'
reply: retcode (250); Msg: 2.0.0 OK 1240421143 4sm652580yxq.48
data: (250, '2.0.0 OK 1240421143 4sm652580yxq.48')
spencewah
  • 2,196
  • 4
  • 20
  • 31

9 Answers9

10

Some self-promotion here, but I feel on a valid ground.

You would literally only need this code to do exactly what you wrote:

import yagmail
yag = yagmail.SMTP('myname@gmail.com')
yag.send('somename@somewhere.com', subject = None, contents = 'Hello')

Or a one liner:

yagmail.SMTP('myname@gmail.com').send('somename@somewhere.com', None, 'Hello world.')

What is nice is that I propose to use keyring to store your password, so you never have a risk of people seeing your password in your script.

You can set this up by running once in your interpreter:

import yagmail
yagmail.register("my@gmail.com", "mypassword")

and exit. Then you can just use:

import yagmail
yagmail.SMTP("my@gmail.com") # without password

If you add .yagmail with "my@gmail.com" in your home dir, then you can just do: yagmail.SMTP(), but that's rather pointless by now.

Warning: If you get serious about sending a lot of messages, better set up OAuth2, yagmail can help with that.

yagmail.SMTP("my@gmail.com", oauth2_file="/path/to/save/creds.json")

The first time ran, it will guide you through the process of getting OAuth2 credentials and store them in the file so that next time you don't need to do anything with it. Do you suspect someone found your credentials? They'll have limited permissions, but you better invalidate their credentials through gmail.

For the package/installation please look at git or readthedocs, available for both Python 2 and 3.

PascalVKooten
  • 20,643
  • 17
  • 103
  • 160
  • 1
    Thanks for the upvote, I'm really trying to get more attention to the package! – PascalVKooten May 03 '15 at 11:00
  • 2
    `SMTPAuthenticationError: Please log in via your web browser and\n5.7.14 then try again.\n5.7.14 Learn more at\n5.7.14 https://support.google.com/mail/answer/78754 vl1sm48001045pbc.31 - gsmtp') ` – Amit Tripathi Oct 29 '15 at 03:07
  • 1
    @Death-Stalker Seems like you made a mistake with writing your password? – PascalVKooten Oct 29 '15 at 08:17
  • no. I tested it like 4-5 times and I am sure my password is right. – Amit Tripathi Oct 29 '15 at 18:13
  • not that I am against your library or anything but why is it so difficult to send an e-mail in python? – Charlie Parker May 01 '18 at 19:30
  • can you explain in more details how to actually make it work? especially the part "What is nice is that I propose to use keyring to store your password, so you never have a risk of people seeing your password in your script." – Charlie Parker May 01 '18 at 21:28
  • 1
    @CharlieParker it's optional though. You can also just have it in your script if you are too lazy to read the documentation. Or you can set up OAuth2. It's all in the docs: http://yagmail.readthedocs.io/ – PascalVKooten May 01 '18 at 22:27
  • 1
    I guess this was one of my earlier posts on stackoverflow. I'll add specifically the keyring part in the answer. – PascalVKooten May 01 '18 at 22:28
  • @PascalVKooten Looks neat. Unfortunately running yagmail.register line produces `NameError: name 'keyring' is not defined`. I see your post is 6 years old so probably something changed. – sh37211 Oct 13 '21 at 01:49
  • 1
    @sh37211 I would recommend to set up an application specific password in gmail and just use that – PascalVKooten Oct 13 '21 at 18:45
8

Have you tried constructing a valid message?

from email.MIMEText import MIMEText

msg = MIMEText('body')
msg['Subject'] = 'subject'
msg['From'] = "..."
msg['Reply-to'] = "..."
msg['To'] = "..."
Toni Ruža
  • 7,462
  • 2
  • 28
  • 31
7

I don't know if OP still cares about this answer, but having found myself here in an effort to troubleshoot a similar problem, hopefully someone else might find this useful. As it turns out, Google has changed the way that they allow their SMTP server to be used. You will want to check a couple of things:

  1. That you are using the same address you used to authenticate as the 'from' address. If I am not mistaken it used to be the case that you could put pretty much whatever you wanted in the from field, but for security purposes many SMTP host sites (including google) now restrict this to the address that has authenticated with them.

  2. Allow your account to be accessed by 'less secure apps' (read: apps we do not generate revenue from). To do that log into your account and navigate here: https://www.google.com/settings/security/lesssecureapps

  3. Use port 587 with tls. Not really sure why but I could never get port 465 to play nice.

Hope this helps somebody else out.

krayzk
  • 877
  • 1
  • 10
  • 19
6

I think that the GMail SMTP server does a reverse DNS lookup on the IP address that you connect from, and refuses the connection if no domain can be found. This is to avoid spammer from using their SMTP server as an open relay.

Martin Cote
  • 28,864
  • 15
  • 75
  • 99
1

You'll need to check your "Sent" folder in GMail, as that's where a message sent from your account to your account will most probably show up.

fucx
  • 141
  • 7
1

I went to the above mentioned link and had 3 different to addresses to send to but I received three emails to the same address and that being the #3 address.

http://mynthon.net/howto/-/python/python%20-%20logging.SMTPHandler-how-to-use-gmail-smtp-server.txt

import logging
import logging.handlers

class TlsSMTPHandler(logging.handlers.SMTPHandler):
def emit(self, record):
    """
    Emit a record.

    Format the record and send it to the specified addressees.
    """
    try:
        import smtplib
        import string # for tls add this line
        try:
            from email.utils import formatdate
        except ImportError:
            formatdate = self.date_time
        port = self.mailport
        if not port:
            port = smtplib.SMTP_PORT
        smtp = smtplib.SMTP(self.mailhost, port)
        msg = self.format(record)
        msg = "From: %s\r\nTo: %s\r\nSubject: %s\r\nDate: %s\r\n\r\n%s" % (
                        self.fromaddr,
                        string.join(self.toaddrs, ","),
                        self.getSubject(record),
                        formatdate(), msg)
        if self.username:
            smtp.ehlo() # for tls add this line
            smtp.starttls() # for tls add this line
            smtp.ehlo() # for tls add this line
            smtp.login(self.username, self.password)
        smtp.sendmail(self.fromaddr, self.toaddrs, msg)
        smtp.quit()
    except (KeyboardInterrupt, SystemExit):
        raise
    except:
        self.handleError(record)

logger = logging.getLogger()

gm = TlsSMTPHandler(("smtp.gmail.com", 587), 'myusername@gmail.com', ['address1@gmail.com', 'address2@gmail.com', 'address3@gmail.com'], 'unable to find Error!', ('myusername@gmail.com', 'mypassword'))
gm.setLevel(logging.ERROR)

logger.addHandler(gm)

try:
    1/0
except:
    logger.exception('It NO work for me!!-')
BartekR
  • 3,827
  • 3
  • 24
  • 33
Jim
  • 11
  • 2
0

It's works

'''
Created on 2017/11/27

@author: devuser
'''

import smtplib
from email.mime.text import MIMEText
from email.utils import formatdate

FROM_ADDRESS = 'sender@gmail.com'
MY_PASSWORD = 'password'
TO_ADDRESS = 'receiver@test.co.jp'
BCC = 'receiver2@test.net'
SUBJECT = 'GmailのSMTPサーバ経由'
BODY = 'pythonでメール送信'


def create_message(from_addr, to_addr, bcc_addrs, subject, body):
    msg = MIMEText(body)
    msg['Subject'] = subject
    msg['From'] = from_addr
    msg['To'] = to_addr
    msg['Bcc'] = bcc_addrs
    msg['Date'] = formatdate()
    return msg


def send(from_addr, to_addrs, msg):
    smtpobj = smtplib.SMTP('smtp.gmail.com', 587)
    smtpobj.ehlo()
    smtpobj.starttls()
    smtpobj.ehlo()
    smtpobj.login(FROM_ADDRESS, MY_PASSWORD)
    smtpobj.sendmail(from_addr, to_addrs, msg.as_string())
    smtpobj.close()


if __name__ == '__main__':

    to_addr = TO_ADDRESS
    subject = SUBJECT
    body = BODY

    msg = create_message(FROM_ADDRESS, to_addr, BCC, subject, body)
    send(FROM_ADDRESS, to_addr, msg)

https://qiita.com/okhrn/items/630a87ce1a44778bbeb1

Ryosuke Hujisawa
  • 2,682
  • 1
  • 17
  • 18
0

I had the same problem but after trying all the suggestions above, turning off VPN helped.

Riyaz Iqbal
  • 71
  • 1
  • 1
  • 3