[mail] Début de templating, internationalisation, html et plain text

le corps du message est régigé en markdown <http://daringfireball.net/projects/markdown/syntax>
que l'on utilise ensuite pour générer à la fois le plain text du
message et la partie html. On a donc besoin du module python markdown
packagé dans python-markdown.
Les headers sont en plain text.
On utilise jinja2 comme moteur de template (le même que celui de django)

Le mail de bienvenue est là en exemple.
This commit is contained in:
Valentin Samir 2013-08-27 20:41:38 +02:00
parent cbbf060fb2
commit bde23e7ca2
8 changed files with 199 additions and 0 deletions

90
gestion/mail/mail.py Normal file
View file

@ -0,0 +1,90 @@
#! /usr/bin/env python
# -*- coding: utf-8 -*-
import os
import jinja2
import sys
from email.header import Header
from email.message import Message
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from markdown import markdown
sys.path.append('/usr/scripts/')
from gestion.email_tools import format_sender
sys.path.pop()
default_language = 'fr'
template_path = '/usr/scripts/gestion/mail/template/'
html_template = template_path + 'html'
html_mutilang_template = template_path + 'html_multilang'
text_mutilang_template = template_path + 'text_multilang'
templateLoader = jinja2.FileSystemLoader( searchpath=["/", template_path] )
templateEnv = jinja2.Environment( loader=templateLoader )
### For an example:
### print generate('bienvenue', {'From':'respbats@crans.org', 'To':'admin@genua.fr', 'lang_info':'English version below'}).as_string()
def submessage(playload, type, charset='utf-8'):
"""Renvois un sous message à mettre dans un message multipart"""
submsg=MIMEText('', type, charset)
del(submsg['Content-Transfer-Encoding'])
submsg['Content-Transfer-Encoding']='8bit'
submsg.set_payload(playload)
return submsg
def htmlmultilang(mail, lang1, lang2, params, lang_info='', charset='utf-8'):
"""Génère un html bilingue"""
file1 = template_path + mail + '/body/' + lang1
file2 = template_path + mail + '/body/' + lang2
if lang1 == lang2 or not os.path.isfile(file2):
txt = templateEnv.get_template(file1).render(params)
html = templateEnv.get_template(html_template).render({'body': markdown(txt)})
return submessage(html.encode(charset), 'html', charset)
else:
txt1 = templateEnv.get_template(file1).render(params)
txt2 = templateEnv.get_template(file2).render(params)
params.update({'lang1':lang1, 'lang2':lang2, 'body1': markdown(txt1), 'body2':markdown(txt2)})
html = templateEnv.get_template(html_mutilang_template).render(params)
return submessage(html.encode(charset), 'html', charset)
def textmultilang(mail, lang1, lang2, params, charset='utf-8'):
"""Génère un plain text bilingue"""
file1 = template_path + mail + '/body/' + lang1
file2 = template_path + mail + '/body/' + lang2
if lang1 == lang2 or not os.path.isfile(file2):
txt = templateEnv.get_template(file1).render(params)
return submessage(txt.encode(charset), 'plain', charset)
else:
txt1 = templateEnv.get_template(file1).render(params)
txt2 = templateEnv.get_template(file2).render(params)
params.update({'body1': txt1, 'body2':txt2})
txt = templateEnv.get_template(text_mutilang_template).render(params)
return submessage(txt.encode(charset), 'plain', charset)
def generate(mail, params, lang=default_language, lang_fallback=default_language, lang_alt='en', charset='utf-8'):
"""Génère un message multipart"""
msg = MIMEMultipart('alternative')
if os.path.isdir(template_path + mail):
for filename in [dir for dir in os.listdir(template_path + mail) if os.path.isdir(template_path + mail + '/' + dir)]:
if os.path.isfile(template_path + mail + '/' + filename + '/' + lang):
lang_tmp = lang
file = template_path + mail + '/' + filename + '/' + lang
else:
lang_tmp = lang_fallback
file = template_path + mail + '/' + filename + '/' + lang_tmp
if filename == 'body':
msg.attach(textmultilang(mail, lang_tmp, lang_alt, params, charset))
msg.attach(htmlmultilang(mail, lang_tmp, lang_alt, params, charset))
else:
txt = templateEnv.get_template(file).render(params)
if filename in ['From', 'To', 'Cc', 'Bcc']:
msg[filename] = format_sender(txt, charset)
else:
msg[filename]=Header(txt.encode(charset), charset)
return msg

View file

@ -0,0 +1 @@
Crans <{{From}}>

View file

@ -0,0 +1 @@
[CRANS] Bienvenue au Cr@ns !

View file

@ -0,0 +1 @@
{{To}}

View file

@ -0,0 +1,67 @@
Bienvenue !
===========
Si tu lis ce mail, c'est que ton inscription à l'association
s'est déroulée correctement.
Le Cr@ns est une association gérée par des étudiants bénévoles pour les
étudiants résidant sur le campus.
Ses membres actifs s'occupent de la maintenance du réseau, des adhésions
(câblages), ainsi que de plusieurs services mis à la disposition de tous ses
adhérents :
* La connexion à Internet en filaire et en wifi [1] ;
* Un wiki, regroupant plein d'informations diverses concernant la vie ici [2] ;
* Les news, fora de discussion abordant divers thèmes [3] ;
* Un serveur IRC [4] ;
* Un serveur de messagerie instantanée Jabber [5] ;
* Un service de messagerie : une adresse mail @crans.org disponible à vie,
fiable, et avec possibilité d'installer des filtres très précis [6] ;
* Un espace personnel de **2Go** sur le serveur des adhérents [7] ;
* Un service d'impression, 24h/24 7j/7, A3 ou A4, couleur ou noir et blanc,
avec ou sans agrafe, à prix coûtant [8] ;
* La télévision par le réseau [9].
Afin d'assurer le bon fonctionnement de ces services, il est
nécessaire que chaque membre respecte du règlement intérieur [10] accepté lors
de son inscription.
La notice d'utilisation des services du CR@NS est disponible à cette adresse :
<https://wiki.crans.org/CransPratique>. Nous conseillons vivement de s'y
reporter aussi bien pour apprendre à utiliser les différents services que pour
résoudre les problèmes éventuellement rencontrés.
Chaque membre intéressé par le fonctionnement de l'association peut contacter
l'équipe technique à <nounous@crans.org> ou l'équipe administrative à
<ca@crans.org> et/ou se rendre aux réunions publiques du Cr@ns [11].
**Aucune connaissance technique préalable n'est requise pour participer !**
**A noter** : l'accès sans authentification aux news et au wiki est limité à
un usage interne au campus.
* Pour accéder depuis l'extérieur au wiki, il faut se créer un compte [12].
* Pour accéder depuis l'extérieur aux news, il faut s'identifier
(Utilisateur : Vivelapa / Mot de passe : ranoia!)
--
Les membres actifs.
[1]: <https://wiki.crans.org/WiFi>
[2]: <https://wiki.crans.org>
[3]: <https://wiki.crans.org/VieCrans/ForumNews>
[4]: <https://wiki.crans.org/VieCrans/UtiliserIrc>
[5]: <https://wiki.crans.org/VieCrans/UtiliserJabber>
[6]: <https://wiki.crans.org/VieCrans/LesMails>
[7]: <https://wiki.crans.org/VieCrans/GestionCompte>
[8]: <https://wiki.crans.org/VieCrans/ImpressionReseau>
[9]: <https://wiki.crans.org/TvReseau>
[10]: <https://wiki.crans.org/CransAdministratif/R%C3%A8glementInt%C3%A9rieur>
[11]: <https://wiki.crans.org/CompteRendusCrans>
[12]: <http://wiki.crans.org/?action=newaccount>
PS: Il t'est conseillé de conserver ce mail à toutes fins utiles

View file

@ -0,0 +1,15 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta http-equiv="Content-Style-Type" content="text/css" />
<meta name="generator" content="pandoc" />
<title></title>
<style type="text/css">code{white-space: pre;}body{max-width: 55em;text-align:justify;}</style>
</head>
<body>
{% block body %}
{{body}}
{% endblock %}
</body>
</html>

View file

@ -0,0 +1,13 @@
{% extends "html" %}
{% block body %}
<p>{{lang_info}}</p>
<div lang="{{lang1}}">
{{body1}}
</div>
<hr/>
<div lang="{{lang2}}">
{{body2}}
</div>
{% endblock %}

View file

@ -0,0 +1,11 @@
{{lang_info}}
{{body1}}
================================================================================
{{body2}}