📜 ⬆️ ⬇️

Sending HTML email

Introduction


Almost every project has to think about sending emails. The main requirements are, in addition to reliability of delivery, the attractiveness and convenience of emails.


The main nuances in the formation of such letters:



Earlier, I used the Ruby Premailer project for generating HTML letters. I even had to start supporting the project (now there is no time for this, the maintainers are welcome).


Now I wanted to avoid the introduction of Ruby, while Node penetrated everywhere.


Juice


Fortunately, the modern Node ecosystem provides rich email capabilities. We chose a chain for forming e-mail in the form of pug- templates, the transformation of these with the help of juice and the substitution of specific data on the backend (we have Perl).


It is assumed that you are using node 6+ , babel (es2015, es2016, es2017, stage-0 presets).


Installation


 npm install gulp-cli -g npm install gulp --save-dev npm install del --save-dev npm install gulp-rename --save-dev npm install gulp-pug --save-dev npm install premailer-gulp-juice --save-dev npm install gulp-postcss --save-dev npm install autoprefixer --save-dev npm install gulp-less --save-dev 

gulpfile.babel.js:


 'use strict'; import gulp from 'gulp'; import mail from './builder/tasks/mail'; gulp.task('mail', mail); 

builder / tasks / mail.js:


 'use strict'; import gulp from 'gulp'; import stylesheets from './mail/stylesheets'; import templates from './mail/templates'; import clean from './mail/clean'; const mail = gulp.series(clean, stylesheets, templates); export default mail; 

builder / tasks / mail / stylesheets.js


 'use strict'; import gulp from 'gulp'; import config from 'config'; import rename from 'gulp-rename'; import postcss from 'gulp-postcss'; import autoprefixer from 'autoprefixer'; import less from 'gulp-less'; const stylesheetsPath = config.get('srcPath') + '/mail/stylesheets'; const stylesheetsGlob = stylesheetsPath + '/**/*.less'; const mailStylesheets = () => { return gulp.src(stylesheetsGlob) .pipe(less()) .pipe(postcss([ autoprefixer({browsers: ['last 2 versions']}), ])) .pipe(gulp.dest(stylesheetsPath)); }; export default mailStylesheets; 

builder / tasks / mail / templates.js:


 'use strict'; import gulp from 'gulp'; import config from 'config'; import pug from 'gulp-pug'; import rename from 'gulp-rename'; import juice from 'premailer-gulp-juice'; const templatesPath = config.get('srcPath') + '/mail'; const mailPath = config.get('mailPath'); const templatesGlob = templatesPath + '/**/*.pug'; const mailTemplates = () => { return gulp.src(templatesGlob) .pipe(rename(path => { path.extname = '.html'; })) .pipe(pug({ client: false })) .pipe(juice({ webResources: { relativeTo: templatesPath, images: 100, strict: true } })) .pipe(gulp.dest(mailPath)); }; export default mailTemplates; 

builder / tasks / mail / clean.js:


 'use strict'; import del from 'del'; import gutil from 'gulp-util'; const clean = done => { return del([ 'mail/*.html', 'src/mail/stylesheets/*.css' ]).then(() => { gutil.log(gutil.colors.green('Delete src/mail/stylesheets/*.css and mail/*.html')); done(); }); }; export default clean; 

A typical template looks like this (generic.pug):


 include base.pug +base tr(height='74') td.b-mail__table-row--heading(align='left', valign='top') , tr td(align='left', valign='top') | <%== $html %> 

Where base.pug:


 mixin base(icon, alreadyEncoded) doctype html head meta(charset="utf8") link(rel="stylesheet", href="/stylesheets/mail.css") body table(width='100%', border='0', cellspacing='0', cellpadding='0') tbody tr td.b-mail(align='center', valign='top', bgcolor='#ffffff') br br table(width='750', border='0', cellspacing='0', cellpadding='0') tbody.b-mail__table tr.b-mail__table-row(height='89') tr.b-mail__table-row td(align='left', valign='top', width='70') img(src='/images/logo.jpg') td(align='left', valign='top') table(width='480', border='0', cellspacing='0', cellpadding='0') tbody if block block td(align='right', valign='top') if alreadyEncoded img.fixed(src!=icon, data-inline-ignore) else if icon img.fixed(src!=icon) br br tr td(align='center', valign='top') 

Actually, the disc is ready, the templates are compiled. Configuring a config module is trivial and optional.


The ready-made disc of the repository is here: https://github.com/premailer/gulp-juice-demo


 gulp mail 

ViewAction, etc.


Many email clients, such as GMail / Inbox, support special actions in message view. Implementing them is as simple as adding the following tags to the message content:


 div(itemscope, itemtype="http://schema.org/EmailMessage") div(itemprop="action", itemscope, itemtype="http://schema.org/ViewAction") link(itemprop="url", href="https://github.com/imlucas/gulp-juice/pull/9") meta(itemprop="name", content="View Pull Request") meta(itemprop="description", content="View this Pull Request on GitHub") 

Read more in the Email Markup section.


Well, a bit of integration with (choose your language, I needed Perl)


 sub prepare_mail_params { my %params = %{ shift() }; my @keys = keys %params; # Camelize params for my $param ( @keys ) { my $new_param = $param; $new_param =~ s/^(\w)/\U$1\E/; next if $new_param eq $param; $params{$new_param} = delete $params{$param}; } %params = ( Type => 'multipart/mixed; charset=UTF-8', From => 'support@ourcompany.co.uk', Subject => '', %params, ); # Mime params for my $param ( keys %params ) { $params{$param} = encode( 'MIME-Header', $params{$param} ); } return \%params; } sub _template_processor { state $instance = Mojo::Template->new( vars => 1, auto_escape => 1, ); return $instance; } sub send_mail { my %params = %{ shift() }; my $html = (delete $params{message}) // ''; my $template = delete $params{template}; my $stash = (delete $params{stash}) // {}; unless ( $template ) { $template = 'generic'; $stash->{html} = $html; } $html = _template_processor()->render_file( Config->directories->{mail}. "/$template.html", $stash, ); $html = encode_utf8( $html ); my $msg = MIME::Lite->new( %{ prepare_mail_params( \%params ) } ); $msg->attach( Type => 'HTML', Data => $html, ); if ( $mail_settings->{method} eq 'sendmail' ) { return $msg->send(); } if ( $mail_settings->{method} eq 'smtp' ) { return $msg->send('smtp', $mail_settings->{host}, Timeout => $mail_settings->{timeout}); } croak "Unknown Config mail.method: ". $mail_settings->{method}; } 

useful links



PS: Thank you pstn for completing the letter templates.


')

Source: https://habr.com/ru/post/317810/


All Articles