43

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 foo@bar.domain.com, 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?

MatthewMartin
  • 32,326
  • 33
  • 105
  • 164
Josh Hunt
  • 14,225
  • 26
  • 79
  • 98

10 Answers10

22

Here is a very simple example:

import smtplib

server = 'mail.server.com'
user = ''
password = ''

recipients = ['user@mail.com', 'other@mail.com']
sender = 'you@mail.com'
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.

Manuel Ceron
  • 8,268
  • 8
  • 31
  • 38
18

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('myusername@gmail.com', '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
jakebrinkmann
  • 704
  • 9
  • 23
  • Thank you for the link, this is a great resource. IMAP4 is more advanced than POP3, but offers more capabilities such as being able to search through headers. – Joansy Dec 03 '15 at 09:06
12

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
bortzmeyer
  • 34,164
  • 12
  • 67
  • 91
  • I hate when people downvote without adding a comment. What was the problem with my answer? – bortzmeyer Dec 09 '08 at 09:03
  • I don't know what the problem would be. It's basically my answer with more details. I think this is a good solution. – epochwolf Dec 17 '08 at 21:05
  • Actually python's smtpd server is pretty good for the internal apps I've used it for. SMTP really isn't all that difficult to get right, the hard part is multiplexing network connections. Not sure I'd use it to handle "real" production load though. – mcrute Dec 24 '08 at 06:17
  • 1
    Thank you for the detailed answer! The same concept should also work on a Windows server, using IIS's native SMTP virtual server. – Lyndsy Simon Jun 15 '12 at 14:11
7

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.

mcrute
  • 1,592
  • 1
  • 16
  • 27
4

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

Bullines
  • 5,626
  • 6
  • 53
  • 93
3

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

Toni Ruža
  • 7,462
  • 2
  • 28
  • 31
2

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)
ambassallo
  • 924
  • 1
  • 12
  • 27
  • This looks needlessly complex to my eye. What do you gain by making this a Windows service, rather than just keeping it as a (platform-independent) thread or process? – Ponkadoodle Jan 11 '16 at 04:31
  • 2
    @Wallacoloo. I wrote this with the windows OS in mind. Something that runs for ever is better run as a windows service. The benefits of a service are definitely worth the added complexity. My humble opinion. – ambassallo Jan 12 '16 at 06:26
2

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.

epochwolf
  • 12,340
  • 15
  • 59
  • 70
0

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()
3DCoded
  • 13
  • 1
  • 6
0

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 = "me@example.com"
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

miksus
  • 2,426
  • 1
  • 18
  • 34