MEAN Stack to Meteorjs – Server Side Email
Moving code from the Mean Stack to Meteor requires a little bit of rewiring and rethinking.
Everyone has a different approach for learning new things. One way I like to learn new frameworks is to start with small elements or functionality and to focus on learning only as I need to know. It also helps me build up a small library of code elements that I can refer back to as needed.
In this post, I’m going to start with an example of using the Mean Stack with Nodemailer to send emails, and replace the expressJs elements with Meteor server side code.
We’ll also change it up slightly for angularJS.
Let’s get into it! We’ll first have a look at the existing Mean Stack code, and then look at the equivalent Meteorjs code:
The Mean Stack
The client side (Angular Code)
In the mean stack, we had the following code in the contact-form.client.controller.js file:
angular.module('core').controller('ContactFormController', ['$scope', '$http', '$mdToast', '$animate', function($scope, $http, $mdToast, $animate) { // Expose view variables $scope.toastPosition = { bottom: false, top: true, left: false, right: true }; $scope.getToastPosition = function () { return Object.keys($scope.toastPosition) .filter(function (pos) { return $scope.toastPosition[pos]; }) .join(' '); }; this.sendMail = function () { var data = ({ contactName : this.contactName, contactEmail : this.contactEmail, contactMsg : this.contactMsg }); // Simple POST request example (passing data) : $http.post('/contact-form', data). success(function(data, status, headers, config) { // this callback will be called asynchronously // when the response is available $mdToast.show( $mdToast.simple() .content('Thanks for your message ' + data.contactName + ' You Rock!') .position($scope.getToastPosition()) .hideDelay(5000) ); }). error(function(data, status, headers, config) { // called asynchronously if an error occurs // or server returns response with an error status. }); }; } ]);
The key thing to note in the code above is that the $http service is being called to post to the
/contact-form
route.
The Express Route (API)
The route, defined in core.server.routes.js looked like this:
module.exports = function(app) { // Root routing var core = require('../controllers/core.server.controller'); ... app.route('/contact-form').post(core.sendMail); };
The Express Controller
The sendMail method referred to by the route (in the core.server.controller.js file) looked like this:
var nodemailer = require('nodemailer'); var transporter = nodemailer.createTransport(); ... /** * Send an email when the contact from is submitted */ exports.sendMail = function(req, res) { var data = req.body; transporter.sendMail({ from: data.contactEmail, to: '[email protected]', subject: 'Message from ' + data.contactName, text: data.contactMsg }); res.json(data); };
Sending emails with Meteor
Meteor has a set of utility packages that you can easily add to your app. The email package makes it easy to send emails from your Meteor app. To use it, add the package to your project.
This goes in your terminal:
$ meteor add email
Meteor (using Angular-Meteor)
The code below is a combination of the meteor docs and this discovermeteor post.
A note from the discover meteor post:
Note that Email.send() has a synchronous API, which means that if it fails, a catchable exception will be thrown straight away. And conversely, if the code that comes afterwards gets executed, we know it means the call succeeded, so we can log the event with confidence.
The client side (Angular Code)
For Angular-meteor, instead of using the $http service, we can just use Meteor.call or Meteor.apply
angular.module('core').controller('ContactFormController', ['$scope', '$mdToast', '$animate', function($scope, $mdToast, $animate) { // Expose view variables $scope.toastPosition = { bottom: false, top: true, left: false, right: true }; $scope.getToastPosition = function () { return Object.keys($scope.toastPosition) .filter(function (pos) { return $scope.toastPosition[pos]; }) .join(' '); }; this.sendMail = function () { var data = ({ contactName : this.contactName, contactEmail : this.contactEmail, contactMsg : this.contactMsg }); Meteor.call('sendEmailMethod', data, function(err, result) { if (err) { console.log(err); } else { // this callback will be called asynchronously // when the response is available $mdToast.show( $mdToast.simple() .content('Thanks for your message ' + result.contactName + ' You Rock!') .position($scope.getToastPosition()) .hideDelay(5000) ); } }); }; } ]);
In the code above we’re using meteor to call the sendEmailMethod method, and passing across the data object.
Server Side Meteor Methods
In this example, we’ll create a new File in the Core module > Server Directory called sendEmail.controller.js
// In your server code: define a method that the client can call Meteor.methods({ sendEmailMethod: function (data) { check([data.contactName, data.contactEmail, data.contactMsg], [String]); console.log(data); // Let other method calls from the same client start running, // without waiting for the email sending to complete. this.unblock(); try { var emailSent = sendEmail(data); console.log('Email successfully sent'); return data; } catch (e) { console.log('Something bad happened!'); } } }); // on the server sendEmail = function(data, text) { Email.send({ from: data.contactEmail, to: '[email protected]', subject: 'Message from ' + data.contactName, text: data.contactMsg }); };
For more on Meteor Methods, check out this reference cheat sheet: https://gentlenode.com/journal/meteor-5-complete-cheatsheet/7
So Shristy, which way is the best today, give the so many choices: mean.js, mean.io, meteor?
which one would you choose to learn and master? which one would you choose for your new project?
thanks.
Hey Ron,
It’s an interesting question!
There has been a lot of movement in meanjs recently, as things gear up towards making 0.4.0 the master. On the other hand I’ve been busy using Loopback in a project this month.
As much as I like the idea of getting things happening faster using frameworks like meteor or loopback, I prefer being able to interact with base packages, especially when dealing with large and complex applications. For new projects, my preference would be to use a customised version of meanjs.