-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathsendmail.py
executable file
·147 lines (117 loc) · 4.96 KB
/
sendmail.py
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
146
147
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
Mass email to list supplied in CSV
This is a console script using Django mail utilities
"""
from __future__ import print_function
import smtplib
import os
import logging
from email.mime.application import MIMEApplication
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
# default charset, select from the list email.charset.CHARSETS
DEFAULT_CHARSET = 'utf-8'
MAX_ATTACHMENT_SIZE = 16777216
class Sender(object):
""" Class to represent SMTP sender. The main purpose of this class is to
reuse SMTP connection when sending multiple emails
"""
sender = None
connection = None
debug = False
logger = None
def __init__(self, smtp_host, username, password, use_tls=False,
use_ssl=False, sender_email=None, debug=False):
if not debug:
if use_tls:
self.connection = smtplib.SMTP(smtp_host, 587)
self.connection.ehlo()
self.connection.starttls()
elif use_ssl:
self.connection = smtplib.SMTP_SSL(smtp_host)
else:
self.connection = smtplib.SMTP(smtp_host)
self.connection.login(username, password)
if sender_email is None:
sender_email = username
self.debug = debug
self.sender = sender_email
self.logger = logging.getLogger('SMTPSender')
def send_mail(self, subj, body, recipients, charset='utf-8', files=None):
""" A shortcut to send multipart/plaintext message """
msg_body = MIMEText(body, _charset=charset)
if not files:
msg = msg_body
else:
msg = MIMEMultipart()
msg.attach(msg_body)
for filename in files:
try:
if os.path.getsize(filename) > MAX_ATTACHMENT_SIZE:
self.logger.error(
"Attachment size is over 10Mb: %s", filename)
continue
fh = open(filename, 'rb')
content = fh.read()
except IOError:
self.logger.error(
"Can't read the attachment content: %s", filename)
return 1
basename = os.path.basename(filename)
part = MIMEApplication(
content, Name=basename,
Content_Disposition='attachment; filename=%s'.format(basename))
msg.attach(part)
msg['Subject'] = subj
msg['from'] = self.sender
msg['To'] = ", ".join(recipients)
self.logger.debug(msg.as_string())
if not self.debug:
self.connection.sendmail(self.sender, recipients, msg.as_string())
if __name__ == '__main__':
import csv
import sys
import argparse
import settings
parser = argparse.ArgumentParser(
description="Send emails to a list of people in CSV read from stdin.\n"
"First line of CSV file will be treated as a header with "
"column names. Field named email will be used as address, "
"all other fields will be used as template variables.")
parser.add_argument('-s', '--subject', type=str,
help='email subject', default='')
parser.add_argument('-a', '--attach', help='attachment',
action='append', default=[])
parser.add_argument('-y', '--yes', action='store_true',
help="whether to really send emails (set to 0) or just "
"output dry run to console")
args = parser.parse_args()
reader = csv.DictReader(sys.stdin)
if 'email' not in reader.fieldnames:
parser.exit(1,
"Input CSV is expected to have a column named 'email\n\n'")
if not args.subject and 'subject' not in reader.fieldnames:
parser.exit(1, "You need to specify subject in the command line or "
"add a 'subject' column into the input CSV file\n\n")
debug = not args.yes
if debug:
logging.basicConfig(level=logging.DEBUG)
sender = Sender(settings.smtp_server, settings.username, settings.password,
settings.use_tls, settings.use_ssl, debug=debug)
def clean_files(flist):
if not flist:
return []
return [l for l in [f.strip() for f in flist.split("\n") if f] if l]
for record in reader:
# CLI parameters have priority over CSV values
subject = args.subject or record['subject']
body = settings.template.format(**record)
files = args.attach + clean_files(record.get('attachment'))
# paths separated by newlines
sender.send_mail(subject, body, [record['email']], files=files)
if debug:
print (
"="*80, "\nThis is an example of emails that would be sent.\n"
"If you want to really send them, add -y to the command.\n\n")