Compare commits

..

14 Commits

8 changed files with 73 additions and 108 deletions

9
.gitignore vendored Normal file
View File

@ -0,0 +1,9 @@
# Editors
*~
*.sw[po]
\#*\#
.\#*
# Python
*.py[cod]
__pycache__

View File

@ -21,11 +21,13 @@ following packages:
1. Clone repo
$ git clone https://forge.april.org/adminsys/spamotron
$ chmod a+x spamotron/mailing.py
$ cd spamotron
$ chmod a+x mailing.py
2. Try it
$ ./spamotron/mailing.py --help
$ ./mailing.py --help
$ ./mailing.py -t test-recipients-data -b test-emailling --dry-run --verbose
## License

View File

@ -1,7 +1,7 @@
#! /usr/bin/env python3
# (C) Olivier Berger 2001-2002
# (C) François Poulain 2019
# (C) François Poulain 2019-2020
#
# 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
@ -22,9 +22,8 @@
# This program is used to mail a message to several recipients, thus
# providing customization for each recipient.
import argparse, csv, sys, re
import argparse, csv, sys
import smtplib, time, mimetypes
from email.header import Header
from email.message import EmailMessage
from jinja2 import Environment, FileSystemLoader, select_autoescape
@ -67,7 +66,9 @@ def read_recipients_datas(args):
with open(args.tofile) as csv_file:
csv_soup = csv.reader(csv_file)
first = [(s.split(":", 1)) for s in csv_soup.__next__()]
header = [(h[0].strip(), h[1].strip() if len(h) == 2 else None) for h in first]
header = [
(h[0].strip().lower(), h[1].strip() if len(h) == 2 else None) for h in first
]
datas = [[s.strip() for s in d] for d in csv_soup]
full_datas = []
for data in datas:
@ -79,7 +80,6 @@ def read_recipients_datas(args):
except Exception:
print("Ligne mal renseignée:", data, file=sys.stderr)
full_datas.append(full_data)
print(datas)
return full_datas
@ -98,17 +98,17 @@ def read_templates(args):
return templates
def read_join(args):
def read_attachments(args):
r = []
for attachement in args.attachement:
for attachement in args.attachement or []:
try:
with open(args.attachement, "rb") as fp:
ctype, encoding = mimetypes.guess_type(args.attachement)
with open(attachement, "rb") as fp:
ctype, encoding = mimetypes.guess_type(attachement)
if ctype is None or encoding is not None:
ctype = "application/octet-stream"
maintype, subtype = ctype.split("/", 1)
metadata = {
"filename": args.attachement,
"filename": attachement,
"maintype": maintype,
"subtype": subtype,
}
@ -119,88 +119,23 @@ def read_join(args):
return r
def replace_values(bodytemplate, values):
body = bodytemplate
for i in range(len(values)):
i = i + 1
pattern = "${{%02d}}" % i
body = body.replace(pattern, values[i - 1])
return body
# patterns for header of the mail
FROMPATTERN = re.compile(r"^From: *(.*)")
SUBJECTPATTERN = re.compile(r"^Subject: *(.*)")
CCPATTERN = re.compile(r"^Cc: *(.*)")
BCCPATTERN = re.compile(r"^Bcc: *(.*)")
REPLYTOPATTERN = re.compile(r"^Reply-To: *(.*)")
def qencode_subject(message):
subjectmatches = re.search(r"^Subject: *(.*)$", message, re.MULTILINE)
if subjectmatches == None:
return message
subjectstr = subjectmatches.group(1)
h = Header(subjectstr, "utf-8")
qsubjectstr = h.encode()
return message.replace(subjectstr, qsubjectstr, 1)
def send_message(message, to, attachments, args):
lines = message.split("\n")
# identify headers in the template
fromvalue = None
subjectvalue = None
ccvalue = None
bccvalue = None
replytovalue = None
for index, line in enumerate(lines):
if not line:
body = "\n".join(lines[index + 1 :])
break
frommatches = FROMPATTERN.match(line)
subjectmatches = SUBJECTPATTERN.match(line)
ccmatches = CCPATTERN.match(line)
bccmatches = BCCPATTERN.match(line)
replytomatches = REPLYTOPATTERN.match(line)
if frommatches:
fromvalue = frommatches.group(1)
if subjectmatches:
subjectvalue = subjectmatches.group(1)
if ccmatches:
ccvalue = ccmatches.group(1)
if bccmatches:
bccvalue = bccmatches.group(1)
if replytomatches:
replytovalue = replytomatches.group(1)
# lists all addresses to which the mail will be sent
dests = [to]
if ccvalue:
dests.append(ccvalue)
if bccvalue:
dests.append(bccvalue)
def send_message(templates, data, attachments, args):
dests = [data["to"]]
msg = EmailMessage()
msg["Subject"] = subjectvalue
msg["From"] = fromvalue
msg["To"] = to
if replytovalue:
msg["Reply-To"] = replytovalue
if ccvalue:
msg["Cc"] = ccvalue
msg.set_content(body)
msg["Subject"] = templates[0].render(**data).strip()
msg["From"] = data["from"]
msg["To"] = data["to"]
if "reply-to" in data:
msg["Reply-To"] = data["reply-to"]
if "cc" in data:
msg["Cc"] = data["cc"]
dests.append(data["cc"])
if "bcc" in data:
dests.append(data["bcc"])
msg.set_content(templates[1].render(**data))
if attachments:
for attachement in attachments:
for attachment in attachments:
msg.add_attachment(attachment[0], **attachment[1])
if args.verbose:
@ -209,7 +144,7 @@ def send_message(message, to, attachments, args):
else:
print(
"Sending : %s, from %s to %s, dests : %s"
% (subjectvalue, fromvalue, dests[0], repr(dests))
% (msg["Subject"], data["from"], dests[0], repr(dests))
)
if not args.dry_run:
@ -227,32 +162,20 @@ if __name__ == "__main__":
# read the recipients file
datas = read_recipients_datas(args)
# read the template of the mail
# read the templates of the mail
templates = read_templates(args)
print(templates)
exit(0)
# optionnaly read the attachment of the mail
attachment = None
if args.attachement:
attachments = read_join(args)
attachments = read_attachments(args)
# counter to be able to pause each 10 mails send
counter = 0
# send mail to each recipient
for set in sets:
values = set
# the recipient is always in first column
recipient = values[0]
# replace substitution variables in the template for each recipient
body = replace_values(bodytemplate, values)
for data in datas:
# send message
send_message(body, recipient, attachments, args)
send_message(templates, data, attachments, args)
# pause every 10 mails for 5 secs so that the MTA doesn't explode
counter = counter + 1

7
test-emailling.footer Normal file
View File

@ -0,0 +1,7 @@
--
Vous disposez d'un droit d'accès, de modification, de rectification et de
suppression des données vous concernant (loi « Informatique et Libertés » du 6
janvier 1978). Pour toute demande, merci de vous adressez à contact@april.org.
Si vous souhaitez ne plus recevoir nos communiqués de presse merci de vous
adressez à contact@april.org.

15
test-emailling.html Normal file
View File

@ -0,0 +1,15 @@
<html>
<header>
<title>
Vive le libre en fête
</title>
</header>
<body>
<p>
Chère {{ nom }},
</p><p>
Venez découvrir le logiciel libre autour du printemps. Déjà 42 événements pour
le Libre en Fête à venir.
</p>
</body>
</html>

1
test-emailling.subject Normal file
View File

@ -0,0 +1 @@
Vivle le libre en fête

4
test-emailling.txt Normal file
View File

@ -0,0 +1,4 @@
Chère {{ nom }},
Venez découvrir le logiciel libre autour du printemps. Déjà 42 événements pour
le Libre en Fête à venir.

4
test-recipients-data Normal file
View File

@ -0,0 +1,4 @@
to,nom,from:president@april.org,cc:contact@april.org,reply-to:contact@april.org
noc@april.org,network operating center
secretaire@april.org,secrétaire,president@paril.org,
prez@april.org,présidente,prez@elysee.fr