Thursday, June 02, 2011

SMTP Relay and CodeIgniter

Any SysAdmin will tell you that having a good toolkit at your disposal makes your job much easier. And if you think about, it's a universal truth. Whatever your profession, you absolutely need the right tools for the job. As a SysAdmin I rely heavily on my toolkit because I know that the process of troubleshooting is much quicker when I have a tool that will uncover that critical bit of information to pinpoint the root cause of a problem, or that critical byte in the case of a recent support issue here at JangoMail.

The JangoMail support team had an issue pop up whereby some users of the CodeIgniter PHP framework were not able to successfully send messages via the JangoMail SMTP relay. A cursory check of our incoming logs showed that in all cases, the SMTP transaction was stalling out at the DATA command. All other parts of the system were in working order and we had no complaints from other users. It was a good time to open up that SysAdmin toolkit and see what else we could dig up.

For my money, Wireshark is an indispensable tool. It has been a lifesaver for me on multiple occasions. The old-school Unix/Linux admin would likely use the tcpdump tool for similar reasons. These tools capture all network traffic on the computer and dump it in a human readable format. Wireshark has an especially nice GUI and a helpful feature to trace an entire TCP stream and decode the application layer protocol as necessary.

Back to our CodeIgniter issue... after firing up Wireshark, it took just one SMTP transaction with CodeIgniter to pinpoint the issue. RFC 2821 requires commands to be terminated with CRLF (that's carriage return followed by line-feed), but the CodeIgniter client was only sending a LF character. As a result, the JangoMail SMTP relay server was waiting for more input until it ultimately timed out, resulting in an un-sent message. One single byte was the reason messages were not flowing!

A quick Google search turned up the fact that CodeIgniter defaults to using only LF as its line terminator, but that can be adjusted. The code to set the proper line terminator is as follows:

$config['crlf'] = "\r\n";
$config['newline'] = "\r\n";

A good illustration of the fact that when communicating between systems on the Internet we should try and follow Internet standards as much as possible. Perhaps it's also time we all finally agree on a single line-terminator. Microsoft's Windows, Apple's OSX and the Linux operating system all use different line-terminator character sequences by default(!) - CRLF, CR and LF respectively.

Solving a problem often comes down to having the right tool for the job. So what does your toolkit look like?