20110815

How to manage emails?

Django has a powerful API for Sending email. But how can we bring this to the end-user? How to configure the generating and sending of emails? What user interface must Lino provide to make this usable?

One thing to note is: the lino.modlib.mails module which I started yesterday is not necessary to answer these questions. The system should work also for those who don’t care about keeping track of what they sent (i.e. who don’t want a history of outgoing mail integrated to their database). That’s why the lino.modlib.mails module can be considered as “almost ready (waiting for a user)”.

Let’s consider a concrete example: a Lino user who organizes travels wants to send booking confirmation to her customers. A Travel, for this customer, is a customized lino.modlib.cal.Event. When somebody registers for a Travel, the user enters the Person as lino.modlib.cal.Attendance of this Travel, with status “to be confirmed”. The Attendance model should have an action “Send E-Mail”. Clicking on this button would generate and send directly a single mail which says something like “We confirm your registration to our travel X. Please find the attached invoice. Your registration will be complete when we received your payment…”.

The template for this mail would be the normal Django way (i.e. using an .eml file somewhere in the templates tree.

The Attendance needs a ForeignKey field that points to the invoice. If that field is empty when “Send E-Mail”, then Lino must first generate the Invoice, run it’s print method to generate a .pdf file to be attached to the email. Calling “Send E-Mail” a second time would of course not generate another invoice but attach the existing .pdf file.

To be more transparent, the “Send E-Mail” action might be only on the Invoice, and the Attendance would rather have an action “Generate Invoice”.

Conclusion: write a lino.mixins.sendable.Sendable mixin that adds a “Send E-Mail” button and a DateTimeField “sent”.

The snippet presented on stackoverflow was a good start. But I didn’t like the idea of having two templates to maintain.

Peter Bengtsson had the same problem in 2007 and wrote html2plaintext before he discovered Aaron Swartz’s html2text module. I included the latter into Lino as lino.utils.html2text.

First success after less than 3 hours. Check-in at 18:30.

Thoughts about templates

lino.mixins.sendable.Sendable currently uses Django’s template system. Yes, Cheetah is more powerful, but not very user-friendly. But in fact we use HTML templates only for the welcome.html and for makedocs. It wouldn’t be too much huge work to go back to Django’s templates… Cheetah or Django templates? templates or config directories?

Even Guido van Rossum preferred Django over Cheetah in 2006 (though he also warns “(BEWARE! I haven’t used either system to build a real website yet. I’m just looking at the API and templating language designs.)”). Eugene Lazutkin wrote in a comment to this article “AFAIK original Django authors decided against using templates as a front for Python interpreter precisely because of this reason: templates should not be able to bring down the system no matter what. They should provide a functionality required by web designers and nothing more. Otherwise it is a huge liability, a potential security hole, and a maintenance nightmare.”

My lino.utils.config exists mainly because Djangos “template seach algorithm” doesn’t allow things like:

  • find a template using Django and then use it for appy.pod
  • return a list of available templates (in a customizable “group”)
  • override a template by another file depending on the language.

As for the template language itself, I simply cannot accept the limitation that it doesn’t allow to pass parameters to functions (the docs say “Because Django intentionally limits the amount of logic processing available in the template language, it is not possible to pass arguments to method calls accessed from within templates.”)

I still don’t really agree to this decision: I find it a pity to cripple down my own possibilities (and those of future Lino application developers) just because other people want to have their templates publicly editable.

After some time on the battle field I must agree that I prefer to write complex document chunks as Python functions. Just look at the welcome.html of Lino/DSBE:

<div>
#if $user is not None
<p>User <b>$user.get_full_name() ($user)</b> on $site.title</p>

#from lino.modlib.cal.models import tasks_summary
$tasks_summary($ui,$user,days_back=90,days_forward=30,
 max_items=10,before='<ul><li>',separator='</li><li>',after="</li></ul>")

#from lino.apps.dsbe.models import persons_by_user
$persons_by_user()

#else
<p>user is None. Check your authentication configuration.</p>
#end if
<p><font size="1">$lino.welcome_html()</font></p>

</div>

But even here it is obvious: that fact of not being able to pass arguments to functions is simply a show stopper for Django templates. Sorry.

Check-in 20110815b at 22:20. The proof of concept has passed. We continue to use Cheetah templates, mainly because Django templates don’t allow to pass arguments to functions.

Todo:

  • sent_time field and refusing to send a second time.
  • preview of the mail that is about to be sent.
  • There can be more than one mail per Attendance: e.g. if confirmed is empty, we send an invitaton. Or more variants depending on status etc.