Completed
Push — master ( 36ad7a...d400da )
by John
01:15
created

prep_smtp_instance()   A

Complexity

Conditions 2

Size

Total Lines 18

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
dl 0
loc 18
rs 9.4285
c 0
b 0
f 0
1
#!/usr/bin/env python3
2
"""This module is used for dealing with SMTP email sending."""
3
4
import smtplib  # smtp connection
5
import configparser  # reading config files
6
import getpass  # passwords
7
import os  # paths
8
from email.mime.text import MIMEText  # email formatting
9
from bbarchivist import utilities  # file work
10
11
__author__ = "Thurask"
12
__license__ = "WTFPL v2"
13
__copyright__ = "Copyright 2015-2016 Thurask"
14
15
16
def smtp_config_loader(homepath=None):
17
    """
18
    Read a ConfigParser file to get email preferences.
19
20
    :param homepath: Folder containing ini file. Default is user directory.
21
    :type homepath: str
22
    """
23
    resultdict = {}
24
    config = configparser.ConfigParser()
25
    if homepath is None:
26
        homepath = os.path.expanduser("~")
27
    conffile = os.path.join(homepath, "bbarchivist.ini")
28
    if not os.path.exists(conffile):
29
        open(conffile, 'w').close()
30
    config.read(conffile)
31
    if not config.has_section('email'):
32
        config['email'] = {}
33
    smtpini = config['email']
34
    resultdict['server'] = smtpini.get('server', fallback=None)
35
    resultdict['port'] = int(smtpini.getint('port', fallback=0))
36
    resultdict['username'] = smtpini.get('username', fallback=None)
37
    resultdict['password'] = smtpini.get('password', fallback=None)
38
    resultdict['is_ssl'] = smtpini.get('is_ssl', fallback=None)
39
    return resultdict
40
41
42
def smtp_config_writer(**kwargs):
43
    """
44
    Write a ConfigParser file to store email server details.
45
46
    :param server: SMTP email server.
47
    :type server: str
48
49
    :param port: Port to use.
50
    :type port: int
51
52
    :param username: Email address.
53
    :type username: str
54
55
    :param password: Email password, optional.
56
    :type password: str
57
58
    :param is_ssl: True if server uses SSL, False if TLS only.
59
    :type is_ssl: bool
60
61
    :param homepath: Folder containing ini file. Default is user directory.
62
    :type homepath: str
63
    """
64
    config = configparser.ConfigParser()
65
    if kwargs['homepath'] is None:
66
        kwargs['homepath'] = os.path.expanduser("~")
67
    conffile = os.path.join(kwargs['homepath'], "bbarchivist.ini")
68
    if not os.path.exists(conffile):
69
        open(conffile, 'w').close()
70
    config.read(conffile)
71
    if not config.has_section('email'):
72
        config['email'] = {}
73
    if kwargs['server'] is not None:
74
        config['email']['server'] = kwargs['server']
75
    if kwargs['port'] is not None:
76
        config['email']['port'] = str(kwargs['port'])
77
    if kwargs['username'] is not None:
78
        config['email']['username'] = kwargs['username']
79
    if kwargs['password'] is not None:
80
        config['email']['password'] = kwargs['password']
81
    if kwargs['is_ssl'] is not None:
82
        config['email']['is_ssl'] = str(kwargs['is_ssl']).lower()
83
    with open(conffile, "w") as configfile:
84
        config.write(configfile)
85
86
87
def smtp_config_generator(results):
88
    """
89
    Take user input to create the SMTP configparser settings.
90
91
    :param results: The results to put in bbarchivist.ini.
92
    :type results: dict
93
    """
94
    if results['server'] is None:
95
        results['server'] = input("SMTP SERVER ADDRESS: ")
96
    if results['port'] == 0:
97
        results['port'] = input("SMTP SERVER PORT: ")
98
    if results['username'] is None:
99
        results['username'] = input("EMAIL ADDRESS: ")
100
    if results['password'] is None:
101
        results['password'] = getpass.getpass(prompt="PASSWORD: ")
102
    if results['is_ssl'] is None:
103
        use_ssl = utilities.s2b(input("Y: SSL, N: TLS (Y/N): "))
104
        if use_ssl:
105
            results['is_ssl'] = "true"
106
        else:
107
            results['is_ssl'] = "false"
108
    return results
109
110
111
def send_email(kwargs):
112
    """
113
    Wrap email sending based on SSL/TLS.
114
115
    :param server: SMTP email server.
116
    :type server: str
117
118
    :param port: Port to use.
119
    :type port: int
120
121
    :param username: Email address.
122
    :type username: str
123
124
    :param password: Email password, optional.
125
    :type password: str
126
127
    :param is_ssl: True if server uses SSL, False if TLS only.
128
    :type is_ssl: bool
129
130
    :param software: Software release.
131
    :type software: str
132
133
    :param os: OS version.
134
    :type os: str
135
136
    :param body: Email message body.
137
    :type body: str
138
    """
139
    if kwargs['password'] is None:
140
        kwargs['password'] = getpass.getpass(prompt="PASSWORD: ")
141
    server, username, port, password = parse_kwargs(kwargs)
142
    subject = generate_subject(kwargs['software'], kwargs['os'])
143
    message = generate_message(kwargs['body'], username, subject)
144
    payload = {
145
        "server": server,
146
        "port": port,
147
        "username": username,
148
        "password": password,
149
        "message": message,
150
        "is_ssl": kwargs["is_ssl"]
151
    }
152
    send_email_post(payload)
153
154
155
def prep_smtp_instance(kwargs):
156
    """
157
    Prepare a smtplib.SMTP/SMTP_SSL instance.
158
159
    :param is_ssl: True if server uses SSL, False if TLS only.
160
    :type is_ssl: bool
161
162
    :param server: SMTP email server.
163
    :type server: str
164
165
    :param port: Port to use.
166
    :type port: int
167
    """
168
    if kwargs['is_ssl']:
169
        smt = smtplib.SMTP_SSL(kwargs['server'], kwargs['port'])
170
    else:
171
        smt = smtplib.SMTP(kwargs['server'], kwargs['port'])
172
    return smt
173
174
175
def send_email_post(kwargs):
176
    """
177
    Send email through SSL/TLS.
178
179
    :param server: SMTP email server.
180
    :type server: str
181
182
    :param port: Port to use.
183
    :type port: int
184
185
    :param username: Email address.
186
    :type username: str
187
188
    :param password: Email password.
189
    :type password: str
190
191
    :param message: Message to send, with body and subject.
192
    :type message: MIMEText
193
    """
194
    smt = prep_smtp_instance(kwargs)
195
    smt.ehlo()
196
    if not kwargs['is_ssl']:
197
        smt.starttls()
198
    smt.login(kwargs['username'], kwargs['password'])
199
    smt.sendmail(kwargs['username'], kwargs['username'], kwargs['message'].as_string())
200
    smt.quit()
201
202
203
def parse_kwargs(kwargs):
204
    """
205
    Extract variables from kwargs.
206
207
    :param server: SMTP email server.
208
    :type server: str
209
210
    :param port: Port to use.
211
    :type port: int
212
213
    :param username: Email address.
214
    :type username: str
215
216
    :param password: Email password, optional.
217
    :type password: str
218
    """
219
    server = kwargs['server']
220
    username = kwargs['username']
221
    port = kwargs['port']
222
    password = kwargs['password']
223
    return server, username, port, password
224
225
226
def generate_message(body, username, subject):
227
    """
228
    Generate message body/headers.
229
230
    :param body: Body of text.
231
    :type body: str
232
233
    :param username: Address to send to and from.
234
    :type username: str
235
236
    :param subject: Subject of message.
237
    :type subject: str
238
    """
239
    msg = MIMEText(body)
240
    msg['Subject'] = subject
241
    msg['From'] = username
242
    msg['To'] = username
243
    return msg
244
245
246
def generate_subject(softwarerelease, osversion):
247
    """
248
    Generate message subject.
249
250
    :param softwarerelease: Software version.
251
    :type softwarerelease: str
252
253
    :param osversion: OS version.
254
    :type osversion: str
255
    """
256
    return "SW {0} - OS {1} available!".format(softwarerelease, osversion)
257
258
259
def prep_email(osversion, softwarerelease, password=None):
260
    """
261
    Bootstrap the whole process.
262
263
    :param osversion: OS version.
264
    :type osversion: str
265
266
    :param softwarerelease: Software version.
267
    :type softwarerelease: str
268
269
    :param password: Email password. None to prompt later.
270
    :type password: str
271
    """
272
    results = smtp_config_loader()
273
    results['homepath'] = None
274
    smtp_config_writer(**results)
1 ignored issue
show
Coding Style introduced by
Usage of * or ** arguments should usually be done with care.

Generally, there is nothing wrong with usage of * or ** arguments. For readability of the code base, we suggest to not over-use these language constructs though.

For more information, we can recommend this blog post from Ned Batchelder including its comments which also touches this aspect.

Loading history...
275
    results['software'] = softwarerelease
276
    results['os'] = osversion
277
    results['body'] = utilities.return_and_delete("TEMPFILE.txt")
278
    if password is not None:
279
        results['password'] = password
280
    send_email(results)
281