Jul
7th
 

Send email with attachments using Python

Posted by admin in Python

Today we will look at a method of using the SMTP protocol via Python. Our goal is to create a class through which we can send emails with attachments.

First, a word about the SMTP protocol.

  • SMTP (Simple Mail Transfer Protocol) is the standard protocol for sending email via internet. By default, SMTP uses port number 25 and the transmission protocol is TCP. One of the first SMTP servers is sendmail, still widely in use, others exist, such as Postfix, Exim.

Ok, on to the code. The main way of sending emails via python is the smtplib.

Create a file called “smtp.py” in your working directory and paste the following code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
import smtplib, os, time, atexit
from email.MIMEMultipart import MIMEMultipart
from email.MIMEBase import MIMEBase
from email.MIMEText import MIMEText
from email.Utils import formatdate
from email import Encoders
 
class ConnectionError(smtplib.SMTPException): pass
class LoginError(smtplib.SMTPException): pass
class DisconnectionError(smtplib.SMTPException): pass
class EmailSendError(smtplib.SMTPException): pass
 
class Smtp:
 
        def __init__(self, host, user, password, port=25):
                self._host        = host
                self._port        = port                
                self._user        = user
                self._password    = password
 
                self._message     = None
                self._subject     = None
                self._from_addr   = None
                self._rcpt_to     = None               
                self._server      = None         
                self._attachments = []
 
                atexit.register(close) #our close() method will be automatically executed upon normal interpreter termination
 
                self.connect()
 
 
        def connect(self):
 
                if all([self._host, self._port, self._user, self._password]):
 
                        try:    
                                self._server = smtplib.SMTP(self._host, self._port)
 
                        except smtplib.SMTPException, e:
                                raise ConnectionError("Connection failed!")
 
                        try:
                                self._server.login(self._user, self._password)        
 
                        except smtplib.SMTPException, e:                                
                                raise LoginError("Login Failed!")
 
 
 
        def close(self):                
 
                if self._server:
                        try:
                                self._server.quit()
 
                        except smtplib.SMTPException, e:                                
                                raise DisconnectionError("Disconnection failed!")
 
 
        def message(self, message):
                self._message = message
 
 
        def subject(self, subject):
                self._subject = subject
 
 
        def from_addr(self, email):
                self._from_addr = email
 
 
        def rcpt_to(self, email):
                self._rcpt_to = email
 
 
        def attach(self, file):
                if os.path.exists(file):
                        self._attachments.append(file)
 
 
        def load_attachments(self, m_message):
                for file in self._attachments:
                        part = MIMEBase('application', "octet-stream")
                        part.set_payload(open(file,"rb").read())
                        Encoders.encode_base64(part)
                        part.add_header('Content-Disposition', 'attachment; filename="%s"' % os.path.basename(file))
                        m_message.attach(part)    
 
                return m_message
 
 
        def send(self, content_type='plain', charset='UTF-8'):
 
                if all([self._message, self._subject, self._from_addr, self._rcpt_to]):                                
 
                        m_message             = MIMEMultipart()
 
                        m_message['From']     = self._from_addr
                        m_message['To']       = self._rcpt_to
                        m_message['Date']     = formatdate(localtime=True)
                        m_message['Subject']  = self._subject
                        m_message['X-Mailer'] = "Python X-Mailer"
 
                        m_message.attach(MIMEText(self._message, content_type, charset))
 
                        m_message = self.load_attachments(m_message)
 
                        try:
                                self._server.sendmail(self._from_addr, self._rcpt_to, m_message.as_string())       
 
                        except smtplib.SMTPException, e:
                                raise EmailSendError("Email has not been sent")

Here we have a simple class ready for sending email over an authenticated connection via python.

Now for the explanation (This should be easy to understand for those of us who already use python a bit).

Skipping over the various module import commands required to run our class, we come to the declaration of 4 classes (from line 8 to 11) needed for error management.

  • ConnectionError – the exception generated if there is a problem in connecting to the SMTP server.
  • Loginerror – the exception generated when there is a problem with the login (user/password).
  • DisconnectionError – the exception generated when there is a problem when disconnecting from SMTP server.
  • EmailSendError – the exception generated when there is a problem in sending the email.

As you can see every exception inherits smtplib.SMTPException. In this way you can also catch our exceptions, by using the baseclass smtplib module.

Now we move on to the explanation of SMTP class

The class has an initialiser for the declaration of all attributes for the class and automatically calls the connect() method to connect to the SMTP server.

Moving on… at line number 33, we meet our connect() method, in which we will create an instance of the SMTP class (smtplib) and will then try to authenticate to the smtp server with self._server.login(). If there are errors in the connection or the login to the server, the two exceptions (ConnectionError, Loginerror) will be generated.

To successfully send an email certain data are needed: the sender, recipient, subject and message. For this reason, using our methods: from_addr(), rcpt_to(), subject(), and message() we will be able to upload all data needed to send our email. In addition to these basic methods, our class has a very useful method for attaching a file or files to our email, attach(file_path).

Now lets give it a try! Create a file named “test.py” in your working directory and paste the following code:

from smtp import Smtp
 
smtp = Smtp("mail.server.com", "user", "password")
smtp.subject('This is a test')
smtp.message('Email message')
smtp.from_addr('from@server.com')
smtp.rcpt_to('to@server.com')
smtp.attach("file1.jpg")
smtp.attach("file2.gif")
smtp.attach("file3.pdf")
smtp.send()

Need more explanation? :-)

Have fun using this!




One Response to “Send email with attachments using Python”

  1. superdrupermegapuper54321…

    Very usefull info. Thanks!…

Leave a Reply

Search



Categories