summaryrefslogtreecommitdiff
path: root/src/gmail.py
blob: 34579b6529331759319a4c0875a11c5e4327693f (plain)
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
114
115
116
117
118
119
120
121
122
123
124
125
#!/usr/bin/env python
# encoding: utf-8

import mimetypes
import os
import smtplib

from email import encoders
from email.mime.base import MIMEBase
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText


class GMail(object):
    """Email sender using the gmail service."""
    SMTPSERVER = 'smtp.gmail.com:587'

    def __init__(self, account, password):
        """
        Initializes the class.
        You should provide credentials in order to login into gmail.

        :param account: the username@gmail.com account to use for sending.
        :type account: str
        :param password: the password for the account.
        :type password: str
        """
        self._from = account
        login = account.split('@')[0]
        self._server = smtplib.SMTP(self.SMTPSERVER)
        self._server.starttls()
        self._server.login(login, password)

    def __del__(self):
        """
        Quits the server.
        """
        self._server.quit()

    def _get_attachment(self, file_path):
        """
        Creates the MIMEBase attachment for the file 'file_path'.

        Might raise:
            IOError

        :param file_path: the file from to generate the attachment from.
        :type file_path: str

        :return: the MIMEBase attachment.
        :rtype: MIMEBase
        """
        ctype, encoding = mimetypes.guess_type(file_path)
        if ctype is None or encoding is not None:
            # No guess could be made, or the file is encoded (compressed),
            # so use a generic bag-of-bits type.
            ctype = 'application/octet-stream'
        maintype, subtype = ctype.split('/', 1)

        # Read the file, this may rise IOError
        with open(file_path, 'rb') as fp:
            the_file = MIMEBase(maintype, subtype)
            the_file.set_payload(fp.read())

        # Encode the payload using Base64
        encoders.encode_base64(the_file)

        # Set the filename parameter
        the_file.add_header('Content-Disposition', 'attachment',
                            filename=os.path.basename(file_path))

        return the_file

    def send_email(self, to_addr_list, cc_addr_list, subject,
                   message, attachments=None):
        """
        Sends an email.

        :param to_addr_list: a list of addresses to send the email.
        :type to_addr_list: list of str
        :param cc_addr_list: a list of addresses to send (as CC) the email.
        :type cc_addr_list: list of str
        :param subject: the subject of the email
        :type subject: str
        :param message: the message to send
        :type message: str
        :param attachments: a list of paths for the files to attach.
        :type attachments: list of str

        :return: an empty dict if everything went ok or
                 the problems result of sending the email(s).
        :rtype: dict
        """
        # Create the container (outer) email message.
        msg = MIMEMultipart()
        msg['Subject'] = subject
        msg['From'] = self._from
        msg['To'] = ', '.join(to_addr_list)

        if cc_addr_list:
            msg['Cc'] = ', '.join(cc_addr_list)

        # Add the message's text
        msg.attach(MIMEText(message))

        problems = ''
        if attachments is not None:
            # Attach every file in the attachment parameter
            for file_path in attachments:
                try:
                    the_file = self._get_attachment(file_path)
                    msg.attach(the_file)
                except IOError:
                    problems += "Could not attach {0!r}\n".format(file_path)

        message = msg.as_string()
        try:
            result = self._server.sendmail(self._from, to_addr_list, message)
        except Exception as e:
            result['Exception'] = repr(e)

        if problems:
            result['Attachments'] = problems

        return result