135 lines
4.2 KiB
Python
Executable file
135 lines
4.2 KiB
Python
Executable file
#! /usr/bin/env python
|
|
# -*- coding: iso-8859-15 -*-
|
|
|
|
# Copyright (C) Stéphane Glondu + ???
|
|
# Licence : ???
|
|
|
|
"""
|
|
Envoi de mails textes encodés et bien formatés (encodages spécifiés là il faut).
|
|
Autres outils relatifs aux mails.
|
|
|
|
format_sender et send_email adaptés depuis /usr/scripts/impression/crans_backend.py.
|
|
"""
|
|
|
|
import re
|
|
|
|
|
|
def format_sender(sender, header_charset='ISO-8859-15'):
|
|
"""
|
|
Check and format sender for header.
|
|
"""
|
|
from email.Header import Header
|
|
from email.Utils import parseaddr, formataddr
|
|
|
|
# Split real name (which is optional) and email address parts
|
|
sender_name, sender_addr = parseaddr(sender)
|
|
|
|
# We must always pass Unicode strings to Header, otherwise it will
|
|
# use RFC 2047 encoding even on plain ASCII strings.
|
|
sender_name = str(Header(unicode(sender_name), header_charset))
|
|
|
|
# Make sure email addresses do not contain non-ASCII characters
|
|
sender_addr = sender_addr.encode('ascii')
|
|
|
|
return formataddr((sender_name, sender_addr))
|
|
|
|
|
|
def send_email(sender, recipient, subject, body, server='localhost', cc=None, debug=False, actual_sender=None):
|
|
"""
|
|
Send an email.
|
|
|
|
All arguments should be Unicode strings (plain ASCII works as well).
|
|
Only the real name part of sender and recipient addresses may contain
|
|
non-ASCII characters. The email will be properly MIME encoded.
|
|
|
|
The charset of the email will be the first one out of US-ASCII, ISO-8859-15
|
|
and UTF-8 that can represent all the characters occurring in the email.
|
|
|
|
Argument server maybe a string, indicating the name of the SMTP server, or
|
|
directly an instance of smtplib.SMTP.
|
|
|
|
The resulting mail will be sent to debug if not False.
|
|
Otherwise, it will be sent to recipient and cc.
|
|
"""
|
|
from smtplib import SMTP
|
|
from email.MIMEText import MIMEText
|
|
from email.Header import Header
|
|
|
|
# Header class is smart enough to try US-ASCII, then the charset we
|
|
# provide, then fall back to UTF-8.
|
|
header_charset = 'ISO-8859-15'
|
|
|
|
# We must choose the body charset manually
|
|
for body_charset in 'US-ASCII', 'ISO-8859-15', 'UTF-8':
|
|
try:
|
|
body.encode(body_charset)
|
|
except UnicodeError:
|
|
pass
|
|
else:
|
|
break
|
|
|
|
sender = format_sender(sender)
|
|
recipient = format_sender(recipient)
|
|
if cc: cc = format_sender(cc)
|
|
|
|
# Create the message ('plain' stands for Content-Type: text/plain)
|
|
msg = MIMEText(body.encode(body_charset), 'plain', body_charset)
|
|
msg['From'] = sender
|
|
msg['To'] = recipient
|
|
msg['Subject'] = Header(unicode(subject), header_charset)
|
|
if cc: msg['Cc'] = cc
|
|
|
|
if debug:
|
|
actual_recipient = [debug]
|
|
else:
|
|
actual_recipient = [recipient]
|
|
if cc: actual_recipient.append(cc)
|
|
|
|
if actual_sender:
|
|
actual_sender = format_sender(actual_sender)
|
|
else:
|
|
actual_sender = sender
|
|
|
|
# Send the message
|
|
if isinstance(server, SMTP):
|
|
server.sendmail(actual_sender, actual_recipient, msg.as_string())
|
|
else:
|
|
smtp = SMTP()
|
|
smtp.connect(server)
|
|
smtp.sendmail(actual_sender, actual_recipient, msg.as_string())
|
|
smtp.quit()
|
|
|
|
|
|
def parse_mail_template(fichier):
|
|
"""
|
|
Lit fichier et renvoie le couple sujet, corps en unicode.
|
|
Les trois premières lignes de fichier doivent être :
|
|
Encoding: <encodage du fichier>
|
|
Subject: <sujet du mail>
|
|
<ligne vide>
|
|
Le reste forme le corps du mail.
|
|
L'argument fichier peut être un nom de fichier, ou directement une
|
|
instance de file.
|
|
"""
|
|
if not isinstance(fichier, file):
|
|
fichier = file(fichier)
|
|
|
|
encoding = fichier.readline()
|
|
matched = re.search(r'^Encoding:\s*([^\r\n]*)', encoding)
|
|
if matched:
|
|
encoding = matched.group(1)
|
|
else:
|
|
raise SyntaxError("Encoding manquant dans template")
|
|
|
|
subject = fichier.readline()
|
|
matched = re.search(r'^Subject:\s*([^\r\n]*)', subject)
|
|
if matched:
|
|
subject = matched.group(1).decode(encoding)
|
|
else:
|
|
raise SyntaxError("Subject manquant dans template")
|
|
|
|
if fichier.readline() not in ['\r\n', '\n']:
|
|
raise SyntaxError("le fichier n'a pas le bon format")
|
|
|
|
body = fichier.read().decode(encoding)
|
|
return subject, body
|