I am trying to send an email using SMTP via python.
This is my code:
import smtplib
from email.mime.text import MIMEText
textfile='msg.txt'
you='ashwin#gmail.com'
me='ashwin#gmail.com'
fp = open(textfile, 'rb')
msg = MIMEText(fp.read())
fp.close()
# me == the sender's email address
# you == the recipient's email address
msg['Subject'] = 'The contents of %s' % textfile
msg['From'] = me
msg['To'] = you
print "reached before s"
s = smtplib.SMTP('127.0.0.1',8000)
print "reached after s"
s.sendmail(me, [you], msg.as_string())
s.quit()
when I try and execute this code, "reached before s" is printed and then goes into an infinite loop or so, i.e. "reached after s" is not printed and the program is still running.
This is code for the server:
import sys
import BaseHTTPServer
from SimpleHTTPServer import SimpleHTTPRequestHandler
HandlerClass = SimpleHTTPRequestHandler
ServerClass = BaseHTTPServer.HTTPServer
Protocol = "HTTP/1.0"
if sys.argv[1:]:
port = int(sys.argv[1])
else:
port = 8000
server_address = ('127.0.0.1', port)
HandlerClass.protocol_version = Protocol
httpd = ServerClass(server_address, HandlerClass)
sa = httpd.socket.getsockname()
print "Serving HTTP on", sa[0], "port", sa[1], "..."
httpd.serve_forever()
can someone figure out what is wrong?
I believe yagmail (disclaimer: I'm the maintainer) can be of great help to you.
Its goal is to make it easy to send emails with attachments.
import yagmail
yag = yagmail.SMTP('ashwin#gmail.com', 'yourpassword')
yag.send(to = 'ashwin#gmail.com', subject ='The contents of msg.txt', contents = 'msg.txt')
That's only three lines indeed.
Note that yagmail contents will try to load the string passed. If it cannot, it will send as text, if it can load it, it will attach it.
If you pass a list of strings, it will try to load each string as a file (or, again, just display the text).
Install with pip install yagmail or pip3 install yagmail for Python 3.
More info at github.
Here is a different approach that creates an email sender class with all the error handling taken care of:
import getpass
import smtplib
class EmailBot(object):
# Gets the username and password and sets up the Gmail connection
def __init__(self):
self.username = \
raw_input('Please enter your Gmail address and hit Enter: ')
self.password = \
getpass.getpass('Please enter the password for this email account and hit Enter: ')
self.server = 'smtp.gmail.com'
self.port = 587
print 'Connecting to the server. Please wait a moment...'
try:
self.session = smtplib.SMTP(self.server, self.port)
self.session.ehlo() # Identifying ourself to the server
self.session.starttls() # Puts the SMTP connection in TLS mode. All SMTP commands that follow will be encrypted
self.session.ehlo()
except smtplib.socket.gaierror:
print 'Error connecting. Please try running the program again later.'
sys.exit() # The program will cleanly exit in such an error
try:
self.session.login(self.username, self.password)
del self.password
except smtplib.SMTPAuthenticationError:
print 'Invalid username (%s) and/or password. Please try running the program again later.'\
% self.username
sys.exit() # program will cleanly exit in such an error
def send_message(self, subject, body):
try:
headers = ['From: ' + self.username, 'Subject: ' + subject,
'To: ' + self.username, 'MIME-Version: 1.0',
'Content-Type: text/html']
headers = '\r\n'.join(headers)
self.session.sendmail(self.username, self.username, headers + '''\r\r''' + body)
except smtplib.socket.timeout:
print 'Socket error while sending message. Please try running the program again later.'
sys.exit() # Program cleanly exits
except:
print "Couldn't send message. Please try running the program again later."
sys.exit() # Program cleanly exits
All you need to do is create an EmailBot instance and call the send_message method on it, with the appropriate details as inputs.
Related
I am trying to send an email from my raspberry pi on startup to get its IP address. I followed this blog: https://elinux.org/RPi_Email_IP_On_Boot_Debian
My code:
__author__ = 'author'
__license__ = "license"
__version__ = "1.0"
__maintainer__ = "maintainer"
__status__ = "Test"
import subprocess
import smtplib
from email.mime.text import MIMEText
import datetime
def connect_type(word_list):
""" This function takes a list of words, then, depeding which key word, returns the corresponding
internet connection type as a string. ie) 'ethernet'.
"""
if 'wlan0' in word_list or 'wlan1' in word_list:
con_type = 'wifi'
elif 'eth0' in word_list:
con_type = 'ethernet'
else:
con_type = 'current'
return con_type
# Change to your own account information
# Account Information
to = 'toemail#gmx.com' # Email to send to.
gmail_user = 'myemail#gmail.com' # Email to send from. (MUST BE GMAIL)
gmail_password = 'mypwd' # Gmail password.
try:
smtpserver = smtplib.SMTP('smtp.gmail.com',587) # Server to use.
smtpserver.set_debuglevel(1)
smtpserver.ehlo() # Says 'hello' to the server
smtpserver.starttls() # Start TLS encryption
smtpserver.ehlo()
smtpserver.login(gmail_user, gmail_password) # Log in to server
today = datetime.date.today() # Get current time/date
arg='ip route list' # Linux command to retrieve ip addresses.
# Runs 'arg' in a 'hidden terminal'.
p=subprocess.Popen(arg,shell=True,stdout=subprocess.PIPE)
data = p.communicate() # Get data from 'p terminal'.
# Split IP text block into three, and divide the two containing IPs into words.
ip_lines = data[0].splitlines()
split_line_a = ip_lines[1].split()
split_line_b = ip_lines[2].split()
# con_type variables for the message text. ex) 'ethernet', 'wifi', etc.
ip_type_a = connect_type(split_line_a)
ip_type_b = connect_type(split_line_b)
"""Because the text 'src' is always followed by an ip address,
we can use the 'index' function to find 'src' and add one to
get the index position of our ip.
"""
ipaddr_a = split_line_a[split_line_a.index('src')+1]
ipaddr_b = split_line_b[split_line_b.index('src')+1]
# Creates a sentence for each ip address.
my_ip_a = 'Your %s ip is %s' % (ip_type_a, ipaddr_a)
my_ip_b = 'Your %s ip is %s' % (ip_type_b, ipaddr_b)
# Creates the text, subject, 'from', and 'to' of the message.
msg = MIMEText(my_ip_a + "\n" + my_ip_b)
msg['Subject'] = 'IPs For RaspberryPi on %s' % today.strftime('%b %d %Y')
msg['From'] = gmail_user
msg['To'] = to
# Sends the message
smtpserver.sendmail(gmail_user, [to], msg.as_string())
# Closes the smtp server.
smtpserver.quit()
except Exception as e:
print ("[ERROR] failed to send mail: " + str(e))
when executing the program, no exception occurs. however, the program tries to connect to the server forever at line
smtpserver = smtplib.SMTP('smtp.gmail.com',587)
and nothing happens.
I can reach the smtp server and port using telnet without any problem. I also enabled less secure apps in my Gmail account.
any suggestions?
So I'm trying to send an email in Iron Python 2.7, and nothing has worked for me. So I combined a bunch of different bits of code I got to try and workaround my issue. Basically, I need to send a zip file without using localhost because I'm assuming the client computer won't have localhost.
Here is my code:
# Send an email
def sendEmail():
# Set standard variables
send_to = ["*******#live.com"]
send_from = "********#outlook.com"
subject = "New Game Info"
text = "Some new info for you. This is an automated message."
assert isinstance(send_to, list)
msg = MIMEMultipart(
From=send_from,
To=COMMASPACE.join(send_to),
Date=formatdate(localtime=True),
Subject=subject
)
print "Created MIME..."
msg.attach(MIMEText(text))
print "Attached message..."
with open("TempLog.zip", "rb") as fil:
msg.attach(MIMEApplication(
fil.read(),
Content_Disposition='attachment; filename="%s"' % "TempLog.zip"
))
print "Attached file..."
server = smtplib.SMTP()
server.connect("smtp-mail.outlook.com", 587)
server.starttls()
server.login("*********#outlook.com", "*****")
server.sendmail("********#outlook.com", send_to, msg.as_string())
server.close()
So as you can see, I have put print statements everywhere to locate the issue. It gets up to "Attached file...," but no further.
I appreciate any help with this issue.
I would suggest using a try/catch block to figure out what the problem really is.
With your current code:
try:
server = smtplib.SMTP()
server.connect("smtp-mail.outlook.com", 587)
server.starttls()
server.login("*********#outlook.com", "*****")
server.sendmail("********#outlook.com", send_to, msg.as_string())
server.close()
except SMTPException, err:
print "ERROR: Unable to send mail - %s" %(err)
except Exception, err:
print "Some other error - %s" %(err)
And for an example that I would suggest putting your host options in the SMTP initialization instead of doing so in connect(). You can modify this example to utilize starttls() as you need.
try:
smtp = smtplib.SMTP(host, port)
smtp.sendmail(sender, receivers, message)
print "Successfully sent email to '%s'" %(receivers)
except SMTPException, err:
print "ERROR: Unable to send mail - %s" %(err)
except Exception, err:
print "Some other error - %s" %(err)
I'm the maintainer of yagmail, a package that tries to make it really easy to send emails.
Maybe you can try this:
import yagmail
yag = yagmail.SMTP(send_from, password, host = 'smtp-mail.outlook.com')
yag.send(send_to, subject = subject, contents = [text, "TempLog.zip"])
This should automatically have "text" as body, and when you give it the location of TempLog.zip, it will automatically detect it is a zip file and attach it.
You might have to install it:
pip install yagmail # Python 2
pip3 install yagmail # Python 3
If something does not work (or when it does), please let me know! I will certainly try to help more.
I following through a tutorial to send an email through python, but it returns an SMTPAuthentication error. Below is my source code:
import smtplib, getpass
# Connect to smtp server
smtpserver = smtplib.SMTP("smtp.gmail.com", 587)
smtpserver.ehlo()
smtpserver.starttls()
smtpserver.ehlo()
print("Successfully connected to gmail.")
# User login
print("Please Login")
gmail_user = str(raw_input("Enter your email: "))
gmail_pwd = getpass.getpass("Enter your password: ")
smtpserver.login(gmail_user, gmail_pwd)
# Destination email
to = str(raw_input("Enter the email you would like to send to: \n"))
# Message contents
header = "To:" + to + "\n" + "From: " + gmail_user + "\n" + "Subject:testing \n"
print header
msg = header + '\n this is test message\n\n'
# Begin sending email
smtpserver.sendmail(gmail_user, to, msg)
print "Success!"
# Close smtpserver
smtpserver.close()
Can anyone tell me what's wrong? I'm pretty sure I typed in the correct email and password. Thanks!
I'm guessing this is the error:
SMTPAuthenticationError: Application-specific password required
You can also try the standard settings of yagmail:
import yagmail
yag = yagmail.Connect(gmail_user, gmail_pwd)
yag.send(to, 'testing', 'this is test message')
yagmail's goal is to make it easy to send gmail messages without all the hassle. It also provides a list of common errors in the documentation.
It also suggests holding the user account in keyring so you never have to write username/pw again (and especially not write it in a script); just run once yagmail.register(gmail_user, gmail_pwd)
Hope to have helped, feel free to check the documentation
I was using Python for sending an email using an external SMTP server. In the code below, I tried using smtp.gmail.com to send an email from a gmail id to some other id. I was able to produce the output with the code below.
import smtplib
from email.MIMEText import MIMEText
import socket
socket.setdefaulttimeout(None)
HOST = "smtp.gmail.com"
PORT = "587"
sender= "somemail#gmail.com"
password = "pass"
receiver= "receiver#somedomain.com"
msg = MIMEText("Hello World")
msg['Subject'] = 'Subject - Hello World'
msg['From'] = sender
msg['To'] = receiver
server = smtplib.SMTP()
server.connect(HOST, PORT)
server.starttls()
server.login(sender,password)
server.sendmail(sender,receiver, msg.as_string())
server.close()
But I have to do the same without the help of an external SMTP server. How can do the same with Python?
Please help.
The best way to achieve this is understand the Fake SMTP code it uses the great smtpd module.
#!/usr/bin/env python
"""A noddy fake smtp server."""
import smtpd
import asyncore
class FakeSMTPServer(smtpd.SMTPServer):
"""A Fake smtp server"""
def __init__(*args, **kwargs):
print "Running fake smtp server on port 25"
smtpd.SMTPServer.__init__(*args, **kwargs)
def process_message(*args, **kwargs):
pass
if __name__ == "__main__":
smtp_server = FakeSMTPServer(('localhost', 25), None)
try:
asyncore.loop()
except KeyboardInterrupt:
smtp_server.close()
To use this, save the above as fake_stmp.py and:
chmod +x fake_smtp.py
sudo ./fake_smtp.py
If you really want to go into more details, then I suggest that you understand the source code of that module.
If that doesn't work try the smtplib:
import smtplib
SERVER = "localhost"
FROM = "sender#example.com"
TO = ["user#example.com"] # must be a list
SUBJECT = "Hello!"
TEXT = "This message was sent with Python's smtplib."
# Prepare actual message
message = """\
From: %s
To: %s
Subject: %s
%s
""" % (FROM, ", ".join(TO), SUBJECT, TEXT)
# Send the mail
server = smtplib.SMTP(SERVER)
server.sendmail(FROM, TO, message)
server.quit()
Most likely, you may already have an SMTP server running on the host that you are working on. If you do ls -l /usr/sbin/sendmail does it show that an executable file (or symlink to another file) exists at this location? If so, then you may be able to use this to send outgoing mail. Try /usr/sbin/sendmail recipient#recipientdomain.com < /path/to/file.txt to send the message contained in /path/to/file.txt to recipient#recipientdomain.com (/path/to/file.txt should be an RFC-compliant email message). If that works, then you can use /usr/sbin/sendmail to send mail from your python script - either by opening a handle to /usr/sbin/sendmail and writing the message to it, or simply by executing the above command from your python script by way of a system call.
I'm trying to make a simple smtp server using the Python smtpd module. I can receive an e-mail and print it out. I try to send an e-mail back to the person who sent me the e-mail with a hello world message and I end up with an infinite loop. I try to use my own server to send the e-mail and it just interprets it as another e-mail that's been received.
How can I use this to both send and receive e-mail?
import smtplib, smtpd
import asyncore
import email.utils
from email.mime.text import MIMEText
import threading
class SMTPReceiver(smtpd.SMTPServer):
def process_message(self, peer, mailfrom, rcpttos, data):
print 'Receiving message from:', peer
print 'Message addressed from:', mailfrom
print 'Message addressed to :', rcpttos
print 'Message length :', len(data)
print data
def send_response():
msg = MIMEText('Hello world!')
msg['To'] = email.utils.formataddr(('Recipient', mailfrom))
msg['From'] = email.utils.formataddr(('Author', 'jsternberg#example.org'))
msg['Subject'] = ''
print 'Connecting to mail server'
server = smtplib.SMTP()
server.set_debuglevel(1)
server.connect()
print 'Attempting to send message'
try:
server.sendmail('jsternberg#example.org', [mailfrom], msg.as_string())
except Exception, ex:
print 'Could not send mail', ex
finally:
server.quit()
print 'Finished sending message'
threading.Thread(target=send_response).start()
return
def main():
server = SMTPReceiver(('', 25), None)
asyncore.loop()
if __name__ == '__main__':
main()
Note: Not using a real e-mail address in the example.
Note 2: Not using this as a mail server. Just want to send/receive simple e-mails for a simple service.
You're not supposed to send the message to yourself...
Perform a MX lookup and send the message to the appropriate SMTP server.