2010-01-12 7 views
7

Comme nous le savons tous (ou devrait), vous pouvez utiliser le système de template de Django pour rendre les corps e-mail:Email templating dans django

def email(email, subject, template, context): 
    from django.core.mail import send_mail 
    from django.template import loader, Context 

    send_mail(subject, loader.get_template(template).render(Context(context)), '[email protected]', [email,]) 

Cela a une faille dans mon esprit: pour modifier le sujet et le contenu d'un email, vous devez éditer à la fois la vue et le modèle. Bien que je puisse justifier de donner aux administrateurs l'accès aux modèles, je ne leur donne pas accès au python brut!

Quelle serait vraiment cool est si vous pouvez spécifier des blocs dans l'e-mail et de les sortir séparément lorsque vous envoyez l'email:

{% block subject %}This is my subject{% endblock %} 
{% block plaintext %}My body{% endblock%} 
{% block html %}My HTML body{% endblock%} 

Mais comment voulez-vous faire? Comment voulez-vous rendre un seul bloc à la fois?

Répondre

11

Ceci est ma troisième itération de travail. Il en supposant que vous avez un modèle de courrier électronique comme ceci:

{% block subject %}{% endblock %} 
{% block plain %}{% endblock %} 
{% block html %}{% endblock %} 

J'ai refactorisé itérer l'envoi d'email sur une liste par défaut et il existe des méthodes utilitaires pour l'envoi d'un e-mail et django.contrib.authUser s (uniques et multiples). Je couvre peut-être plus que ce dont j'ai besoin, mais voilà.

Je pourrais aussi être allé au-dessus avec Python-amour.

def email_list(to_list, template_path, context_dict): 
    from django.core.mail import send_mail 
    from django.template import loader, Context 

    nodes = dict((n.name, n) for n in loader.get_template(template_path).nodelist if n.__class__.__name__ == 'BlockNode') 
    con = Context(context_dict) 
    r = lambda n: nodes[n].render(con) 

    for address in to_list: 
     send_mail(r('subject'), r('plain'), '[email protected]', [address,]) 

def email(to, template_path, context_dict): 
    return email_list([to,], template_path, context_dict) 

def email_user(user, template_path, context_dict): 
    return email_list([user.email,], template_path, context_dict) 

def email_users(user_list, template_path, context_dict): 
    return email_list([user.email for user in user_list], template_path, context_dict) 

Comme toujours, si vous pouvez améliorer cela, faites-le.

+0

Well & * $ # moi. Ça marche. Envisager d'ajouter plus de champs à la base pour permettre de définir les paramètres from/from-name/reply-to. – Oli

+0

Hah, je l'ai fait avec trois modèles différents qui est un PITA. Défini +1 de moi! –

+0

J'aime ça. J'ai toujours utilisé des modèles séparés, ce qui fonctionne bien, mais c'est beaucoup plus agréable à gérer (d'autant plus que vous voulez généralement le même contexte pour tous les modèles de toute façon). –

0

Utilisez simplement deux modèles: un pour le corps et un pour le sujet.

+0

Deux fichiers signifie deux noms de fichiers pour essentiellement la même chose. C'est juste une douleur dans le dos d'avoir à garder au-dessus de ces nombreux modèles. – Oli

0

Je ne pouvais pas obtenir l'héritage de modèle pour travailler en utilisant les {% body %} balises, donc je suis passé à un modèle comme celui-ci:

{% extends "base.txt" %} 

{% if subject %}Subject{% endif %} 
{% if body %}Email body{% endif %} 
{% if html %}<p>HTML body</p>{% endif %} 

Maintenant, nous devons rendre trois fois le modèle, mais l'héritage fonctionne correctement.

c = Context(context, autoescape = False) 
subject = render_to_string(template_name, {'subject': True}, c).strip() 
body = render_to_string(template_name, {'body': True}, c).strip() 
c = Context(context, autoescape = True) 
html = render_to_string(template_name, {'html': True}, c).strip() 

Je trouve aussi qu'il est nécessaire de désactiver autoescape lors du rendu du texte non HTML pour éviter que le texte échappé dans l'e-mail