Scalable and reliable way of sending email from your app

If you are running a web app, chances are that you'll have to send email notifications to your users' inbox either during registration or when doing sending sort of alerts. Mail is still one of the most reliable forms of communications out there.

But email is a dirty game.

Email has garnered a bad rap having been abused by spammers, email marketers and crappy mail clients. No one can look at their inbox and feel proud.

The most ordinary way of sending email from within your app is calling your programing language mail in-built mail function. This talks to local server as the mail relay server. For instance php has the mail function which helps you send email using localhost.

<?php  
// the message
$msg = "First line of text\nSecond line of text";

// use wordwrap() if lines are longer than 70 characters
$msg = wordwrap($msg,70);

// send email
mail("someone@example.com","My subject",$msg);  
?>

Or if you want to send through some external mail server via SMTP authentication, then you can use a third party library such as PhpMailer to send email like this;

<?php  
require("class.phpmailer.php");  
require("class.smtp.php");  
$mail = new PHPMailer();
$mail->IsSMTP(); 
$mail->Host = "mail.davidokwii.com"; // specify SMTP serve
$mail->SMTPAuth = true; // turn on SMTP authentication

$mail->Username = "test@davidokwii.com"; // SMTP username 
$mail->Password = "my-password"; // SMTP password
$mail->From = "test@davidokwii.com"; //From Address 
$mail->addCc('test@live.com,'Test Okwii'); //Cc address
$mail->addBcc('test@yahoo.com','Test OKwii'); //Bcc address
$mail->FromName = "PHP SMTP Test";
$mail->AddAddress("test@gmail.com", "David Test"); //To Address 
$mail->AddReplyTo("test@davidokwii.com", "David Test"); //Reply-To Address

$mail->Port = "25"; // SMTP Port
$mail->WordWrap = 50; // set word wrap to 50 characters
$mail->IsHTML(false); // set email format to HTML
$mail->Subject = "Sending a test email";
$body="
Hello, 

This is a test email

";
$mail->MsgHTML($body);

if(!$mail->Send()){  
    echo "Mailer Error: " . $mail->ErrorInfo;
}
echo $body;  
?>

or Python developers

    SERVER = 'localhost'
    msg_subject = msg_subject
    msg_body = msg_body
    sender = "askari@i3c.co.ug"
    recipients = ['test@gmail.com', 'test@live.com'] 
    msg = MIMEText("""%s""" % msg_body)
    msg['Subject'] = msg_subject
    msg['To'] =  ", ".join(recipients)
    try:
        server = smtplib.SMTP(SERVER)
        server.sendmail(sender, recipients, msg.as_string())
        server.quit()
        print 'successfully sent the mail'
    except:

This approach has several problems.

For starters, you must have installed mail server on local machine which should handle all mail sending functions. Setting up and configuring a mail server is no easy feat. Trust me, I have done it several times, but don't wish to do it again.

Plus once your server is setup, maintenance is another issue. You must ensure that your server is first of all not compromised by spammers to send out unsolicited mails. If it is, your mail server IP is blacklisted and soon your cloud VPS provider will disable your account if the problem persists consequently bringing your application to a halt.

Then, there's making sure that emails sent out from your mail server actually reach the user's inbox. Not the spam folder. Usually big email service providers like Gmail will push emails from unsuspecting mail servers or mail servers whose IP reputation is not known to the user's spam folder. You manually have to instruct your user to check their spam folder to incoming mails.

It's a mess.

A more reliable and scalable way for developers to send out email is using reputable online mail/smtp relay service providers.

You have probably had about mailchimp. You do well. However, there are several -- more than 10 -- mail relay service providers you can use to send out critical emails that actually reach your intended users' inbox via some kind of API. Some of these include; mailgun, sendgrid, postmark, gmail, amazon, ses, mailjet, mandrill, smtp.com etc. Metachris.com has a very illustrative comparitive list which you can checkout for details.

mail relay service providers

Most of these providers are running a paid-for service apart from gmail. However, some have a freemium model which allows you only a certain volume of emails/day or per month on the free package beyond which you have to pay a certain fee.

Sending email through mailgun

I have tested out mailgun and so far am impressed. They have a very elaborate API which you can use to send out emails. They also have a generous freemium offer of 10,000 emails per month.

mailgun website

Once you signup for an account, mailgun will ask you to add a domain. So lets say you have an awesome app called http://orderpizza.com where your users can order any kind of pizza and you wish to send them order receipts via email. Usually with that domain, you probably have already signed up with Google G suit or any other service and receive emails through that domain.

Mailgun recommends that you create a subdomain which you can use specifically for sending and receiving mail from the app. So you can create a subdomain such as mail.orderpizza.com.

Mailgun requires that you verify this domain by adding specific DNS records to it. You do this at your registrar's website or whoever is hosting the DNS records of your domain. You can read more about DNS from my earlier article on DNS for web developers. TXT records in the form of SPF and DKIM are required to send and receive email with Mailgun. This helps Mailgun to fight spam.

SPF records specify which hosts (e-mail servers) are permitted to send e-mail from a particular domain name while a DKIM (DomainKeys Identified Mail) record adds a digital signature to emails your organization sends. You can read more about SPF records here and DKIM here.

mailgun dns settings

You can verify that the DNS records are added to your domain using dig linux command line tool or online tools such as Mxtoolbox or IntoDNS.

~ » dig txt mail.orderpizza.com +nocomments

; <<>> DiG 9.10.3-P4-Ubuntu <<>> txt mail.orderpizza.com +nocomments
;; global options: +cmd
;mail.orderpizza.com.         IN      TXT
mail.orderpizza.com.  86390   IN      TXT     "v=spf1 include:mailgun.org ~all"  
;; Query time: 28 msec
;; SERVER: 127.0.1.1#53(127.0.1.1)
;; WHEN: Thu Jul 13 16:16:32 EAT 2017
;; MSG SIZE  rcvd: 94

Optionally, You may have to add MX record to your domain, so that your recipients can reply to your email messages.

It takes about 24 hours to verify your domain. You might shorten that time by simply clicking on "verify dns records" button.

Once your domain is verified, sending email through your app using the mailgun api is dead simple. You can make your http requests using your native language libraries such as php cURL for PHP, requests library for Python guys or you can use Mailgun's language specific APIs and integrate them with your App.

~ » curl -s --user 'api:key-XXXXXXXXXXXXXXXXXX' \                                                 https://api.mailgun.net/v3/mail.orderpizza.com/messages \
    -F from='Excited User <mailgun@mail.orderpizza.com>' \
    -F to=test@gmail.com \   
    -F subject='Hello' \
    -F text='Testing some Mailgun awesomness!'
{
  "id": "<20170713091025.32561.AF0436CCC906CA7B@mail.orderpizza.com>",
  "message": "Queued. Thank you."
}%

The full API documentation is available here for your further reading.

Mailgun also gives your logs and analytics which show you mail delivery status, opened, clicked, unsubscribed etc.

mailgun logs

So that's it. Sending mails through an external provider makes your API portable; meaning you won't have headache migrating it to another host or running the app via multiple servers. If you have any tips and tricks am happy to hear about them in the comments below.

Image: cantondataprint.com

David Okwii

David Okwii is a Systems Engineer who currently works with Uganda's country code top-level domain registry.

Kampala Uganda http://www.davidokwii.com

Subscribe to oquidave@geek:~ #

Get the latest posts delivered right to your inbox.

or subscribe via RSS with Feedly!