A few years ago a wrote a tutorial for sending emails in an Ionic Framework Android and iOS application. The tutorial works great, but it requires that a mail application be used to finalize the send. In other words, you can set default values for email fields, but you still need to select Gmail or similar to actually send the email.
A popular question I receive is how to send emails without launching an email application. There are a few solutions to this. You could either set up your own server that sends emails and access it via an API, or you can use a service like the Mailgun.
We’re going to see how to send emails using the Mailgun API service.
Let me start by saying that Mailgun has a free tier that in many cases is more than enough. The free tier can accomplish everything I need. You’ll also need to create an account to use Mailgun.
With a Mailgun account established we can now create a new Ionic Framework application. From the Command Prompt (Windows) or Terminal (Mac and Linux), execute the following commands:
ionic start MailgunProject blank --v1
cd MailgunProject
ionic platform add ios
ionic platform add android
A few things to note in the above commands. First, we are creating an Ionic Framework app, not an Ionic 2 app, hence the –v1 tag. The Ionic CLI should default to Ionic Framework if you don’t specify the tag. Second, if you’re not using a Mac then you cannot add and build for iOS.
We’re going to start by creating our application logic. Open the project’s www/js/app.js file and include the following source code:
angular.module('starter', ['ionic'])
.run(function($ionicPlatform) {
$ionicPlatform.ready(function() {
if(window.cordova && window.cordova.plugins.Keyboard) {
cordova.plugins.Keyboard.hideKeyboardAccessoryBar(true);
cordova.plugins.Keyboard.disableScroll(true);
}
if(window.StatusBar) {
StatusBar.styleDefault();
}
});
})
.controller("MailgunController", function($scope, $http) {
var mailgunUrl = "YOUR_DOMAIN_HERE";
var mailgunApiKey = window.btoa("api:key-YOUR_API_KEY_HERE")
$scope.send = function(recipient, subject, message) {
$http(
{
"method": "POST",
"url": "https://api.mailgun.net/v3/" + mailgunUrl + "/messages",
"headers": {
"Content-Type": "application/x-www-form-urlencoded",
"Authorization": "Basic " + mailgunApiKey
},
data: "from=" + "test@example.com" + "&to=" + recipient + "&subject=" + subject + "&text=" + message
}
).then(function(success) {
console.log("SUCCESS " + JSON.stringify(success));
}, function(error) {
console.log("ERROR " + JSON.stringify(error));
});
}
})
There is a lot happening in the above file, particularly in the MailgunController
, so let’s break it down.
To send emails with Mailgun you need to know your configured domain and the API key for that domain. For demonstration purposes I’m just using the sandbox domain, but you might be using something different. The API expects that the API key is base64 encoded. Since Ionic Framework is just a web application, we can use the window.btoa
function to do this.
Now for where the main magic happens, the send
function.
The Mailgun API expects a POST request that contains form data, not JSON data. We can define this requirement in the headers
section of the request. In the headers
section we also need to pass in the base64 encoded authorization token.
Finally we have the request content. Again this is not JSON, so it must be serialized form data. I just demonstrated the basics when it comes to content, but you could include multiple recipients, as well as a cc or bcc field.
Our application logic is now complete. Now we can have a look at the UI of the application.
The application now needs a nice UI for sending emails. Instead of dealing with the AngularJS UI-Router, we’re going to just create this form in the www/index.html file. It will keep things simple for us.
Open the www/index.html file and include the following code:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="initial-scale=1, maximum-scale=1, user-scalable=no, width=device-width">
<meta http-equiv="Content-Security-Policy" content="default-src *; style-src 'self' 'unsafe-inline'; script-src 'self' 'unsafe-inline' 'unsafe-eval'">
<title></title>
<link href="lib/ionic/css/ionic.css" rel="stylesheet">
<link href="css/style.css" rel="stylesheet">
<!-- IF using Sass (run gulp sass first), then uncomment below and remove the CSS includes above
<link href="css/ionic.app.css" rel="stylesheet">
-->
<!-- ionic/angularjs js -->
<script src="lib/ionic/js/ionic.bundle.js"></script>
<!-- cordova script (this will be a 404 during development) -->
<script src="cordova.js"></script>
<!-- your app's js -->
<script src="js/app.js"></script>
</head>
<body ng-app="starter">
<ion-pane>
<ion-header-bar class="bar-stable">
<h1 class="title">Ionic Blank Starter</h1>
</ion-header-bar>
<ion-content ng-controller="MailgunController">
<div class="list">
<label class="item item-input">
<input type="text" placeholder="Recipient (To)" ng-model="recipient">
</label>
<label class="item item-input">
<input type="text" placeholder="Subject" ng-model="subject">
</label>
<label class="item item-input">
<textarea placeholder="Message" ng-model="message"></textarea>
</label>
</div>
<button class="button button-block button-positive" ng-click="send(recipient, subject, message)">
Send
</button>
</ion-content>
</ion-pane>
</body>
</html>
Most of this file was provided to us in the blank template, so I’m going to point out what we’re working with.
Because the application contacts remote web services we need to add a whitelist in the head
tags:
<meta http-equiv="Content-Security-Policy" content="default-src *; style-src 'self' 'unsafe-inline'; script-src 'self' 'unsafe-inline' 'unsafe-eval'">
More can be seen on the topic of whitelisting in my previous post on the subject.
Now we can look at the form we’re creating in this page:
<ion-content ng-controller="MailgunController">
<div class="list">
<label class="item item-input">
<input type="text" placeholder="Recipient (To)" ng-model="recipient">
</label>
<label class="item item-input">
<input type="text" placeholder="Subject" ng-model="subject">
</label>
<label class="item item-input">
<textarea placeholder="Message" ng-model="message"></textarea>
</label>
</div>
<button class="button button-block button-positive" ng-click="send(recipient, subject, message)">
Send
</button>
</ion-content>
We attach the MailgunController
that we created in the AngularJS file and add three form input fields. By using ng-model
the fields are bound to the controller.
The button
will call the controller send
function when clicked, passing in the fields from the form.
If you don’t want to force your users to send emails via one of the installed mailing applications, you don’t have to. An example use case would be if you want to create your own custom email form or if you want to send crash logs without prompting the user. Using a service like the Mailgun API this becomes possible, while being essentially free.