Build Mail
MailMessage
MailMessage
class provides multiple APIs which you can use to build your mails.
This package currently is built on handlebars templating engine. We are planning to support more engines in future.
Built-In Template
Building mails doesn't have to be difficult and time-consuming, that's why Mailman ships with a set of mail builder APIs that makes it easier to build mails without having to define views for every mail that the system rolls out.
We ship an in-built template that you can use for all your transactional and internal communication emails. A sample usage of a mail built with builder APIs,
import { MailMessage } from '@squareboat/nest-mailman';
export class TestmailService {
toMail() {
const mail = MailMessage.init()
.greeting('Hello Sarah,')
.line("You've received a new enquiry")
.line('Summary: The product looks promising! would love to setup a call to discuss more')
.action('View Enquiry', 'https://app.test.in/admin/queries/123');
.subject('INVOICE PAID: #12345');
}
}
The above snippet will generate the following view:
Cool, right! 😎
Here is a list of the available handy methods (We are working on improving these so that they are more flexible and customizable.)
Method | Description |
---|---|
greeting(text) | Sets the greeting for a mail. Rendered with a <h1> tag |
line(text) | Adds text wrapped with a line break |
action(text, link) | Renders a link as a button anchoring the passed text. We value accessibility and so every action also adds the link as a fallback just in case the link is not properly rendered(Check the footer in the previous image) |
Templating
How boring would be email development if it weren't for the templating engines out there?
Mailman supports various methods of templating mails that pretty much cover most of the email development requirements.
Handlebars Templates
Handlebars is Mailmans default templating engine. You can plug in the handlebars template for a mail by calling view('templateFileName')
on MailMessage
instance.
- Behind the scenes mailman looks for this file in the directory that is specified in the
path
key of the configuration object. - Mailman also suffixes the template path with .hbs extension.
Assuming your templates live in '/resources/mails', you could have a template like this:
<p style="white-space: pre;">
Hello {{name}}
Welcome to our platform!
Thank you!
</p>
Now to use the template, simply call the view method passing it the filename and the necessary payload.
import { MailMessage } from '@squareboat/nest-mailman';
export class TestmailService {
toMail() {
const user = { name: 'John Doe' };
const mail = MailMessage.init()
.subject(`${user.name}, welcome to our platform!`);
.view('welcome', user) // payload is optional
}
}
welcome
will automatically get resolved to /project-dir/resources/mails/welcome.hbs
file and the payload passed along will be used to render dynamic content.
Markdown
For developers who strive for simplicity and don't want to get into the hassle of writing HTML, we support markdown. And for this to work we require zero additional configuration at your end. Pass in the markdown filename and you are good to go.
# Brace yourself for our next release!
Howdy people we are super excited to bring together this updated documentation!
> A lot of **new features** too!
Cheers!
Usage:
const mail = MailMessage.init()
.subject('Mailmans upcoming release');
.view('release.md')
Handlebars + Markdown
Additionally, markdown is also registered as a handlebar helper and can be used within handlebars template as follows:
<p style='color: rgb(199, 146, 234);'>Some styled element</p>
{{#markdown}}
# Heading
All the markdown stuff goes here
{{/markdown}}
<footer style='background-color: #fff; color: #f2f2f2;'>Styled footer</p>
The construct can be used like any other handlebars helper, by wrapping the markdown content in {{#markdown}}{{/markdown}}
.
MJML
All good till now, but something is missing, a drum roll and a velvet curtain perhaps! No flex but we've added MJML to Mailman and it calls for a rewrite(Just kidding!)
MJML is the framework for building responsive e-mails. And we couldn't have gotten far in Mailman without this. If you are new to MJML, do check out their documentation at mjml.io
We start off by creating a .mjml
file and specifying the filename to the same old view()
method of MailMessage
const user = { name: 'John Doe' };
const mail = MailMessage.init()
.subject('Introduing our newsletter');
.view('newsletterCampaign')
But there is a catch here, MJML on its own does not support dynamic content. You can create a responsive layout but it's static and you might not be able to customize it per your wish. To overcome this shortcoming we have added handlebars templating power to MJML.
Sample usage - Handlebars + MJML
@Injectable()
export class TestmailService {
toMail() {
const mailMessage = new MailMessage();
mailMessage
.subject('Black Friday SALE!!')
.view('promotional', {
// MJML options for a mail
// Can also be defined globally when configuring mailman module
mjml: {
minify: true,
},
// Payload for the dynamic content
headline: 'Earthen me',
permalink: 'https://earthen.me',
delivery: 'Earthen me office, Delhi',
postal: '110001',
});
Mailman.init().to('jessie@gmail.com').send(mailMessage);
}
}
And inside promotional.hbs
<mj-section full-width="full-width">
<mj-column width="66.66666666666666%" vertical-align="middle">
<mj-text align="left" font-size="11px" padding-bottom="0px" padding-top="0">
<span style="font-size: 11px">{{headline}}</span>
</mj-text>
</mj-column>
<mj-column width="33.33333333333333%" vertical-align="middle">
<mj-text align="right" font-size="11px" padding-bottom="0px" padding-top="0"><span style="font-size: 11px">
<a href="https://mjml.io" style="text-decoration: none; color: inherit;">{{permalink}}</a>
</span></mj-text>
</mj-column>
</mj-section>
Raw Template Strings
Sometimes our mails are small enough and do not need to be defined in a separate template file. For such cases, you can simply use the raw()
method, with the template string and payload.
const user = { name: 'John Doe' };
const mail = MailMessage.init()
.subject(`${user.name}, welcome to our platform!`);
.raw('Hello {{name}}, <br />Welcome to our platform!<br />Thank you!', user)
Attachments
To attach file(s) with your email, you can make use of attach()
method.
Parameter | Description |
---|---|
filename | filename to be reported as the name of the attached file. |
content | Attachment Object |
mail.attach('license', {
path: 'https://raw.githubusercontent.com/squareboat/nest-mailman/main/LICENSE.md',
});
Subject
To set the subject for the mail, you can call the subject('MAIL SUBJECT')
method on mailMessage.
mail.subject('Invoice #12345 has been paid. Yay!')
Debugging Mails
Sometimes, you may want to see the final template that will be built out of the mail object.
This can be extremely helpful to check if your mail is using the dynamic content as intended. Another quick usage is to check the HTML rendered by calling the various Mail builder methods.
You can do so by calling the render method, which returns the complete HTML string that will be sent in the mail.
const rawHtml = 'Hello {{name}}, <br />Welcome to our platform!<br />Thank you!'
const user = { name: 'John Doe' };
const mail = MailMessage.init()
.raw(rawHtml, user)
.subject(`${user.name}, welcome to our platform!`);
console.log(mail.render()); // Hello John Doe, <br />Welcome to our platform!<br />Thank you!
Custom MailMessage
While MailMessage on its own is sufficient in most cases, there can be situations where you may want to add some piece of logic that is specific to a mail. To solve this, you can subclass MailMessage and add in methods on top of MailMessage.
For this to work, you need to implement the handle()
method, which will return the mail body.
import { MailMessage } from '@squareboat/nest-mailman';
export class InvoicePaid extends MailMessage {
constructor(private order: Record<string, any>) {
super();
}
handle(): this {
// write any business logic that you may want to add here
return this.greeting('Hello admin')
.line(`One of your invoices ${this.order.id} has been paid!`)
.action('Check invoice', 'https://squareboat.com')
.line('Please let us know if you are facing any issue!')
.subject(`INVOICE PAID: ${this.order.id}`);
}
}