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?

Asked By: Josh Hunt

||

Answers:

poplib and smtplib will be your friends when developing your app.

Answered By: Bullines

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.

Answered By: mcrute

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.

Answered By: Manuel Ceron

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.

Answered By: epochwolf

The sending part has been covered, for the receiving you can use pop or imap

Answered By: Toni Ruža

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:

  1. For sendmail and Postfix, a ~/.forward containing "|/path/to/program"
  2. If you use procmail, a recipe action of |path/to/program
  3. And certainly many others
Answered By: bortzmeyer

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
Answered By: jakebrinkmann

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)
Answered By: ambassallo

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()
Answered By: smattar

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

Answered By: miksus
Categories: questions Tags: ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.