-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathnewsletter.py
executable file
·127 lines (105 loc) · 5.16 KB
/
newsletter.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
#!/usr/bin/env python3
"""
This program is designed to send our regular newsletter[1] to a list of
students. Its essentially a mass-mailing script with defaults that fit our
needs.
This script is written in pure python 3
[1] http://fsinf.at/newsletter
Copyright 2009, 2010 Mathias Ertl
Copyright 2021 David Kaufmann
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
"""
import argparse
# import subprocess
import sys
import time
import smtplib
from email.message import EmailMessage
from email.policy import SMTPUTF8
parser = argparse.ArgumentParser(
description='Newsletter sending script.',
formatter_class=argparse.ArgumentDefaultsHelpFormatter)
parser.add_argument('-s', '--subject', default='Newsletter der Fachschaft Informatik',
help="Subject of the mail")
parser.add_argument('-f', '--from', dest='frm', default='Fachschaft Informatik <[email protected]>',
help="From header of the mail")
parser.add_argument('-t', '--to', default='[email protected]',
help="To header of the mail. The addresses will receive the mail mulitiple times if the number of recipients is larger than --count.")
parser.add_argument('--recipients', default="recipients.txt", metavar="FILE",
help="A file that lists all the recipients, one on each line")
parser.add_argument('--blacklist', default="blacklist.txt", metavar="FILE",
help="A file that lists all the recipients that no longer want to receive this newsletter - same format as the \"recipients\" parameter")
parser.add_argument('--newsletter', default="newsletter.txt", metavar="FILE",
help="A file containing the text for this newsletter")
parser.add_argument('--header', default="header.txt", metavar="FILE",
help="A file containing a header prefixed to every newsletter")
parser.add_argument('--no-header', action='store_true', default=False,
help="Do not prefix this newsletter with a header")
parser.add_argument('--footer', default="footer.txt", metavar="FILE",
help="A file containing a footer suffixed to every newsletter")
parser.add_argument('--no-footer', action='store_true', default=False,
help="Do not suffix this newsletter with a footer")
parser.add_argument('--print-mail', action='store_true', default=False,
help="Print the mail as it would be send and exit.")
parser.add_argument('--count', default=100, type=int, metavar='N',
help="Send to N recipients at once")
parser.add_argument('--sleep', default=120, type=int, metavar='SECS',
help="Sleep SECS seconds before sending the next mail")
parser.add_argument('--dry-run', default=False, action="store_true",
help="Don't really send mail, only act like it")
parser.add_argument('--personalized', default=False, action="store_true",
help="Send one mail per address, also put address in TO header, implies count=1")
args = parser.parse_args()
# read files
recipients = open(args.recipients).read().splitlines()
blacklist = open(args.blacklist).read().splitlines()
newsletter = open(args.newsletter, 'r').read()
header, footer = "", ""
if not args.no_header:
header = open(args.header, 'r').read()
if not args.no_footer:
footer = open(args.footer, 'r').read()
# remove email addresses contained in blacklist
for entry in blacklist:
recipients = [r for r in recipients if entry not in r]
offset = 0
while offset < len(recipients):
# print number of addresses still to handle and clear line
print('Mails to send: {}\u001b[0K'.format(len(recipients)-offset), end="\r")
sys.stdout.flush()
mail = EmailMessage(policy=SMTPUTF8)
mail.add_header("From", args.frm)
if args.personalized:
mail.add_header("To", recipients[offset])
else:
mail.add_header("To", args.to)
# add recipients to bcc
bcc_list = recipients[offset:][:args.count]
mail.add_header("Bcc", ', '.join(bcc_list))
mail.add_header("Subject", args.subject)
mail.add_header("MIME-Version", "1.0")
# quoted-printable is still more common, but we have upstream autoconvert, so stick to utf8
mail.set_content("{}{}{}".format(header, newsletter, footer), charset="utf-8", cte="8bit")
if args.print_mail:
print(mail)
sys.exit()
if not args.dry_run:
smtp = smtplib.SMTP("localhost")
smtp.send_message(mail)
# increment counter
if args.personalized:
offset += 1
else:
offset += args.count
time.sleep(args.sleep)
# print "Done" and clear line
print("Done.\u001b[0K")