Testing Email (language inspecific)
Friday, September 26th, 2008When testing applications, say a contact form emailer, you probably want to display the actual email, and not just some source code of the email. Some reasons why you may want to do this include (but aren’t limited to):
- View the formatting of an email if it’s HTML
- Check colors, fonts, sizes, and the general flow of the email
- Maybe more comfortable with that way of looking at it (through an email client)
- Want to compare more accurately two different emails
- Want to make sure emails actually send…
Here’s the problem…
Lets say you’re working on a number of projects, and you have your test data but some of that test data may have real emails – say to end users. The worst thing you want to do is to send a test email to a user when they aren’t expecting it. To get their opinion is important, so not disabling mail totally may be important.
Because recently I came across this issue, I wanted to come up with some solutions – more language nonspecific ones to handle the situation.
Option 1:
You can have a variable set that denotes your system is a test system, and doesn’t send the email. Different frameworks handle this differently. One internal to my current job did this – and instead, stuck the email in a log that was in the database. Other frameworks stick this email in a buffer that you can view later. This definitely is a solution, and works pretty well, but not perfect in my opinion. The reason being is you don’t really see the email as the end user would see it. You know it exists, and that works to a degree, but outside that…you don’t see that much.
Option 2:
Have each of the emails going to stdout. So when you send an email, it outputs to the terminal. This suffers the same issues as Option 1, and is done in some frameworks. This is better than option 1 though, because it’s easily able to be seen. No querying of special output buffers, no checking the database, it’s all right there. The problem this suffers mostly with is with say a thousand emails, this doesn’t scale. This is currently a debate on the django project, since it doesn’t support either of these features in a development environment. Read more about it here:
http://code.djangoproject.com/ticket/8638
Option 3:
The third option is just to make sure each of your emails in fixtures is to your own, or a test. Unfortunately while this solves the problems for option 1 and 2, you can make a mistake and something gets sent. Furthermore, if you’re commenting out code on emailing the business owner then you’re really doing it wrong in my opinion. For testing, your code really shouldn’t change.
Option 4:
This option came up as being the most benefit for myself, as of last night (having thought about this for while). Many know I run my development environment in a virtual machine – not on the base system. So what I did was install postfix, and disable the email sending outbound (local accounts will work). Furthermore, this solves all the above problems!. Your code isn’t changing, and it actually gets to sendmail – where we are making a decision to trust sendmail (or postfix) at this point. Personally I’m OK with that…anyways I feel this allows you to fully test emails since you can either tail the email log for when they come in (like some frameworks going to stdout basically do), or you can test in an email viewer quite easily. I really like this option, although implementing it was a bit of a pain.
I want to discuss the steps I went through to make this work for me. Unfortunately, I’m not a postfix expert, and there are a few steps I’m not sure why were needed. Especially the /etc/aliases file needing to have a map to myself…so if anyone can see improvements on this, please comment and I will add your changes and give you credit.
Here are the steps:
Postfix Setup (for generic emails):
1. Install postfix
2. Edit /etc/postfix/main.cf
— mail_spool_directory = /your/spool/directory
— Comment out ‘home_mailbox = .maildir/’
— alias_maps = hash:/etc/aliases
3. Edit /etc/aliases
— Add an alias, e.g. dthole:dthole
— run ‘postalias /etc/aliases’
4. Disable smtp out and in.
— Edit /etc/postfix/master.cf
— Comment out both lines that have smpt in the beginning.
5. Add an always_bcc
— Reedit /etc/postfix/main.cf
— Add always_bcc=yourname@localhost
What the above actually do is force sendmail not to actually send anything out, but the always_bcc local will always deliver it to youname@localhost. This email won’t be a bounce, but will be the actual email itself. From there, just setup your Thunderbird email client, or whatever, to access the unix mail file. If you use virtual machines, you can either create a simlink for this, or just make maildir your home directory (basically re-commenting it out).
If there are other ideas, I’ll post them below as well.
I did quite a bit of discussion on IRC about this with some postfix geeks before posting, and one option another mentioned was the use of defer_transports, to throttle it off. I’m not sure how that works, and the documentation didn’t help the most so I’ll let that up to a commenter to give more details.