Receive and send emails in python
Question:
How can I receive and send email in python? A ‘mail server’ of sorts.
I am looking into making an app that listens to see if it receives an email addressed to [email protected], and sends an email to the sender.
Now, am I able to do this all in python, would it be best to use 3rd party libraries?
Answers:
poplib and smtplib will be your friends when developing your app.
Python has an SMTPD module that will be helpful to you for writing a server. You’ll probably also want the SMTP module to do the re-send. Both modules are in the standard library at least since version 2.3.
Here is a very simple example:
import smtplib
server = 'mail.server.com'
user = ''
password = ''
recipients = ['[email protected]', '[email protected]']
sender = '[email protected]'
message = 'Hello World'
session = smtplib.SMTP(server)
# if your SMTP server doesn't need authentications,
# you don't need the following line:
session.login(user, password)
session.sendmail(sender, recipients, message)
For more options, error handling, etc, look at the smtplib module documentation.
Depending on the amount of mail you are sending you might want to look into using a real mail server like postifx or sendmail (*nix systems) Both of those programs have the ability to send a received mail to a program based on the email address.
I do not think it would be a good idea to write a real mail server in Python. This is certainly possible (see mcrute’s and Manuel Ceron’s posts to have details) but it is a lot of work when you think of everything that a real mail server must handle (queuing, retransmission, dealing with spam, etc).
You should explain in more detail what you need. If you just want to react to incoming email, I would suggest to configure the mail server to call a program when it receives the email. This program could do what it wants (updating a database, creating a file, talking to another Python program).
To call an arbitrary program from the mail server, you have several choices:
- For sendmail and Postfix, a
~/.forward
containing "|/path/to/program"
- If you use procmail, a recipe action of
|path/to/program
- And certainly many others
Found a helpful example for reading emails by connecting using IMAP:
Python — imaplib IMAP example with Gmail
import imaplib
mail = imaplib.IMAP4_SSL('imap.gmail.com')
mail.login('[email protected]', 'mypassword')
mail.list()
# Out: list of "folders" aka labels in gmail.
mail.select("inbox") # connect to inbox.
result, data = mail.search(None, "ALL")
ids = data[0] # data is a list.
id_list = ids.split() # ids is a space separated string
latest_email_id = id_list[-1] # get the latest
# fetch the email body (RFC822) for the given ID
result, data = mail.fetch(latest_email_id, "(RFC822)")
raw_email = data[0][1] # here's the body, which is raw text of the whole email
# including headers and alternate payloads
The best way to do this would be to create a windows service in python that receives the emails using imaplib2
Below is a sample python script to do the same.You can install this script to run as a windows service by running the following command on the command line “python THENAMEOFYOURSCRIPTFILE.py install”.
import win32service
import win32event
import servicemanager
import socket
import imaplib2, time
from threading import *
import smtplib
from email.MIMEMultipart import MIMEMultipart
from email.MIMEText import MIMEText
import datetime
import email
class Idler(object):
def __init__(self, conn):
self.thread = Thread(target=self.idle)
self.M = conn
self.event = Event()
def start(self):
self.thread.start()
def stop(self):
self.event.set()
def join(self):
self.thread.join()
def idle(self):
while True:
if self.event.isSet():
return
self.needsync = False
def callback(args):
if not self.event.isSet():
self.needsync = True
self.event.set()
self.M.idle(callback=callback)
self.event.wait()
if self.needsync:
self.event.clear()
self.dosync()
def dosync(self):
#DO SOMETHING HERE WHEN YOU RECEIVE YOUR EMAIL
class AppServerSvc (win32serviceutil.ServiceFramework):
_svc_name_ = "receiveemail"
_svc_display_name_ = "receiveemail"
def __init__(self,args):
win32serviceutil.ServiceFramework.__init__(self,args)
self.hWaitStop = win32event.CreateEvent(None,0,0,None)
socket.setdefaulttimeout(60)
def SvcStop(self):
self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING)
win32event.SetEvent(self.hWaitStop)
def SvcDoRun(self):
servicemanager.LogMsg(servicemanager.EVENTLOG_INFORMATION_TYPE,
servicemanager.PYS_SERVICE_STARTED,
(self._svc_name_,''))
self.main()
def main(self):
M = imaplib2.IMAP4_SSL("imap.gmail.com", 993)
M.login("YourID", "password")
M.select("INBOX")
idler = Idler(M)
idler.start()
while True:
time.sleep(1*60)
idler.stop()
idler.join()
M.close()
M.logout()
if __name__ == '__main__':
win32serviceutil.HandleCommandLine(AppServerSvc)
You can use emailpy
Install via pip3 install emailpy
import emailpy
manager = emailpy.EmailManager('your email', 'your password')
msg = manager.send(['who you are sending to', 'the other email you are sending to', subject='hello', body='this email is sent from Python', html='<h1>Hello World!</h1>', attachments=['yourfile.txt', 'yourotherfile.py'])
while not msg.sent:
pass
print('sent')
messages = manager.read()
for message in messages:
print(message.sender, message.date, message.subject, message.body, message.html, message.attachments)
for attachment in message.attachments:
print(attachment.name)
attachment.download()
I am the author for two libraries that could solve the problem:
First we configure Red Mail and Red Box:
from redbox import EmailBox
from redmail import EmailSender
USERNAME = "[email protected]"
PASSWORD = "<PASSWORD>"
box = EmailBox(
host="imap.example.com",
port=993,
username=USERNAME,
password=PASSWORD
)
sender = EmailSender(
host="smtp.example.com",
port=587,
username=USERNAME,
password=PASSWORD
)
Then we read the email box with Red Box:
from redbox.query import UNSEEN
# Select an email folder
inbox = box["INBOX"]
# Search and process messages
for msg in inbox.search(UNSEEN):
# Set the message as read/seen
msg.read()
# Get attribute of the message
sender = msg.from_
subject = msg.subject
Lastly we send an email with Red Mail:
sender.send(
subject='You sent a message',
receivers=[sender],
text=f"Hi, you sent this: '{subject}'.",
)
Install the libraries
pip install redbox redmail
Links:
Red Box
Red Mail
How can I receive and send email in python? A ‘mail server’ of sorts.
I am looking into making an app that listens to see if it receives an email addressed to [email protected], and sends an email to the sender.
Now, am I able to do this all in python, would it be best to use 3rd party libraries?
poplib and smtplib will be your friends when developing your app.
Python has an SMTPD module that will be helpful to you for writing a server. You’ll probably also want the SMTP module to do the re-send. Both modules are in the standard library at least since version 2.3.
Here is a very simple example:
import smtplib
server = 'mail.server.com'
user = ''
password = ''
recipients = ['[email protected]', '[email protected]']
sender = '[email protected]'
message = 'Hello World'
session = smtplib.SMTP(server)
# if your SMTP server doesn't need authentications,
# you don't need the following line:
session.login(user, password)
session.sendmail(sender, recipients, message)
For more options, error handling, etc, look at the smtplib module documentation.
Depending on the amount of mail you are sending you might want to look into using a real mail server like postifx or sendmail (*nix systems) Both of those programs have the ability to send a received mail to a program based on the email address.
I do not think it would be a good idea to write a real mail server in Python. This is certainly possible (see mcrute’s and Manuel Ceron’s posts to have details) but it is a lot of work when you think of everything that a real mail server must handle (queuing, retransmission, dealing with spam, etc).
You should explain in more detail what you need. If you just want to react to incoming email, I would suggest to configure the mail server to call a program when it receives the email. This program could do what it wants (updating a database, creating a file, talking to another Python program).
To call an arbitrary program from the mail server, you have several choices:
- For sendmail and Postfix, a
~/.forward
containing"|/path/to/program"
- If you use procmail, a recipe action of
|path/to/program
- And certainly many others
Found a helpful example for reading emails by connecting using IMAP:
Python — imaplib IMAP example with Gmail
import imaplib
mail = imaplib.IMAP4_SSL('imap.gmail.com')
mail.login('[email protected]', 'mypassword')
mail.list()
# Out: list of "folders" aka labels in gmail.
mail.select("inbox") # connect to inbox.
result, data = mail.search(None, "ALL")
ids = data[0] # data is a list.
id_list = ids.split() # ids is a space separated string
latest_email_id = id_list[-1] # get the latest
# fetch the email body (RFC822) for the given ID
result, data = mail.fetch(latest_email_id, "(RFC822)")
raw_email = data[0][1] # here's the body, which is raw text of the whole email
# including headers and alternate payloads
The best way to do this would be to create a windows service in python that receives the emails using imaplib2
Below is a sample python script to do the same.You can install this script to run as a windows service by running the following command on the command line “python THENAMEOFYOURSCRIPTFILE.py install”.
import win32service
import win32event
import servicemanager
import socket
import imaplib2, time
from threading import *
import smtplib
from email.MIMEMultipart import MIMEMultipart
from email.MIMEText import MIMEText
import datetime
import email
class Idler(object):
def __init__(self, conn):
self.thread = Thread(target=self.idle)
self.M = conn
self.event = Event()
def start(self):
self.thread.start()
def stop(self):
self.event.set()
def join(self):
self.thread.join()
def idle(self):
while True:
if self.event.isSet():
return
self.needsync = False
def callback(args):
if not self.event.isSet():
self.needsync = True
self.event.set()
self.M.idle(callback=callback)
self.event.wait()
if self.needsync:
self.event.clear()
self.dosync()
def dosync(self):
#DO SOMETHING HERE WHEN YOU RECEIVE YOUR EMAIL
class AppServerSvc (win32serviceutil.ServiceFramework):
_svc_name_ = "receiveemail"
_svc_display_name_ = "receiveemail"
def __init__(self,args):
win32serviceutil.ServiceFramework.__init__(self,args)
self.hWaitStop = win32event.CreateEvent(None,0,0,None)
socket.setdefaulttimeout(60)
def SvcStop(self):
self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING)
win32event.SetEvent(self.hWaitStop)
def SvcDoRun(self):
servicemanager.LogMsg(servicemanager.EVENTLOG_INFORMATION_TYPE,
servicemanager.PYS_SERVICE_STARTED,
(self._svc_name_,''))
self.main()
def main(self):
M = imaplib2.IMAP4_SSL("imap.gmail.com", 993)
M.login("YourID", "password")
M.select("INBOX")
idler = Idler(M)
idler.start()
while True:
time.sleep(1*60)
idler.stop()
idler.join()
M.close()
M.logout()
if __name__ == '__main__':
win32serviceutil.HandleCommandLine(AppServerSvc)
You can use emailpy
Install via pip3 install emailpy
import emailpy
manager = emailpy.EmailManager('your email', 'your password')
msg = manager.send(['who you are sending to', 'the other email you are sending to', subject='hello', body='this email is sent from Python', html='<h1>Hello World!</h1>', attachments=['yourfile.txt', 'yourotherfile.py'])
while not msg.sent:
pass
print('sent')
messages = manager.read()
for message in messages:
print(message.sender, message.date, message.subject, message.body, message.html, message.attachments)
for attachment in message.attachments:
print(attachment.name)
attachment.download()
I am the author for two libraries that could solve the problem:
First we configure Red Mail and Red Box:
from redbox import EmailBox
from redmail import EmailSender
USERNAME = "[email protected]"
PASSWORD = "<PASSWORD>"
box = EmailBox(
host="imap.example.com",
port=993,
username=USERNAME,
password=PASSWORD
)
sender = EmailSender(
host="smtp.example.com",
port=587,
username=USERNAME,
password=PASSWORD
)
Then we read the email box with Red Box:
from redbox.query import UNSEEN
# Select an email folder
inbox = box["INBOX"]
# Search and process messages
for msg in inbox.search(UNSEEN):
# Set the message as read/seen
msg.read()
# Get attribute of the message
sender = msg.from_
subject = msg.subject
Lastly we send an email with Red Mail:
sender.send(
subject='You sent a message',
receivers=[sender],
text=f"Hi, you sent this: '{subject}'.",
)
Install the libraries
pip install redbox redmail
Links:
Red Box
Red Mail