summaryrefslogtreecommitdiff
path: root/src/gmail.py
blob: 4e7af04679e882eb1e01aec0f3f34a51d5bd8248 (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
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
#!/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

    def send_email_string(self, mail, to):
        """
        Sends an email from an already created email as a string.

        :param mail: the mail to send
        :type mail: str
        :param to: a address to send the email.
        :type to: str

        :return: an empty dict if everything went ok or
                 the problems result of sending the email(s).
        :rtype: dict
        """
        try:
            result = self._server.sendmail(self._from, [to], mail)
        except Exception as e:
            result = {'Exception': repr(e)}

        return result