In this tutorial, I’ll show you how to add email-sending functionality in Bun.js, a modern JavaScript runtime known for its speed and Node.js compatibility.
More precisely, I’ll break down two primary ways to send emails in Bun.js:
- Using Nodemailer and Mailtrap SMTP
- Using Mailtrap email API
Before diving in, ensure you have the following prerequisites:
- Bun.js installed: Follow the official Bun installation guide if you haven’t installed Bun yet. (Bun.js website)
- Mailtrap account: Sign up for a free Mailtrap account and set up a Sending Domain to send emails via their SMTP or API.
Disclaimer: Every bit of code in this article has been prepared and tested by a developer before publication.
Send Email in Bun.js using Nodemailer
Using Nodemailer (a zero-dependency Node.js module for emails) with Bun lets you send emails via an SMTP server of your choice. This is useful if you want to use a solution like Mailtrap SMTP for developer and product teams. Focused on fast delivery and high inboxing rates for transactional and promo emails.
Let’s start with a simple use case: sending a plain-text email.
- Install and import Nodemailer
Make sure Nodemailer is installed in your project. Then import it in your Bun script or application. For example, in an ES module context: import nodemailer from 'nodemailer';
- Configure the SMTP transporter
Create a transporter object with your SMTP server details. This includes the host, port, and authentication credentials. You can find these credentials on your Mailtrap inbox’s SMTP settings page.
Here’s how you might configure the transporter for Mailtrap’s sandbox SMTP:
import nodemailer from "nodemailer";
const transporter = nodemailer.createTransport({
host: "live.smtp.mailtrap.io",
port: 587,
auth: {
user: "1a2b3c4d5e6f7g", // Mailtrap SMTP username (example)
pass: "1a2b3c4d5e6f7g" // Mailtrap SMTP password (example)
}
});
Important: In the snippet above, make sure to replace the user and pass with your Mailtrap SMTP credentials.
- Configure the
mailOptions
Define the email content and recipients in a mailOptions
object. At minimum, specify the sender from
, recipient(s) to
, subject
, and the body
of the email. For a plain-text email, use the text
field for the message. For example:
const mailOptions = {
from: 'you@your-mailtrap-domain.com', // sender address
to: 'friend@example.com', // list of receivers (comma-separated or array)
subject: 'Hello from Bun.js!', // Subject line
text: 'This is a test email sent from a Bun.js app using Nodemailer.' // plain text body
};
- Send the email
Use the transporter’s sendMail()
method to send the message. This method takes the mail options and a callback or returns a Promise. Here’s an example using a callback to log the result:
transporter.sendMail(mailOptions, (error, info) => {
if (error) {
console.error('Error:', error);
} else {
console.log('Email sent:', info.response);
}
});
After updating index.ts file generated from project initialization, the final code would look like this:
import nodemailer from "nodemailer";
const transporter = nodemailer.createTransport({
host: "live.smtp.mailtrap.io",
port: 587,
auth: {
user: "api",
pass: "1a2b3c4d5e6f7g",
},
});
const mailOptions = {
from: "you@example.com",
to: "friend@example.com",
subject: "Hello from Bun.js!",
text: "This is a test email sent from a Bun.js app using Nodemailer.",
};
transporter.sendMail(mailOptions, (error, info) => {
if (error) {
console.error("Error:", error);
} else {
console.log("Email sent:", info.response);
}
});
When you run your Bun script (e.g., bun run index.ts
), this will attempt to send the email via the configured SMTP server.
If successful, you should see a confirmation message with the SMTP server’s response. On error, it will log the error. Nodemailer takes care of the low-level SMTP commands for you, so sending an email is as easy as the above few steps.
(base) user@device bun % bun run index.ts
Email sent: 250 2.0.0 Ok: queued
Additionally, you can check the Mailtrap Email Logs to verify that the email has been sent properly.
With the basics covered for plain text, let’s see how to extend this to HTML emails, attachments, and multiple recipients.
Send HTML email
Nodemailer supports sending HTML emails by simply adding an html
field to the mailOptions
. The html
field can contain your HTML string. It’s good practice to still include a plain-text version for email clients that prefer plain text.
For example, here’s a code snippet with both HTML and plain text:
const mailOptions = {
from: 'you@example.com',
to: 'friend@example.com',
subject: 'Welcome to our service',
text: 'Welcome onboard!', // plain text version
html: '<h1>Welcome!</h1><p>We are excited to have you onboard.</p>'
};
In the above snippet, the html
content will be used as the email body for clients that can display HTML, while the text
serves as a fallback. You can use any HTML tags, inline CSS (though support varies by email client), and even include dynamic content or templates.
Send email with attachment
To send attachments (files like PDFs, images, etc.) with Nodemailer, you can add an attachments
array in the mail options. Each attachment can be specified with properties like filename
and either a path
to the file or raw content
. Additionally, Nodemailer is quite flexible: you can attach files from disk, streams, buffers, or even data URLs.
For example, suppose you want to attach a PDF invoice stored on disk:
const mailOptions = {
... // (other fields like from, to, etc.)
subject: 'Your invoice',
text: 'Please find your invoice attached.',
attachments: [
{
filename: 'invoice.pdf',
path: '/path/to/invoice.pdf' // path to file on your server
}
]
};
When Nodemailer sends this email, it will read the file at the given path and include it as an attachment. You can specify multiple objects in the attachments array to send more than one file. Instead of path, you could use content to provide file data (for example, a Buffer or base64 string) and even specify a contentType if needed.
To display an image within the HTML of the email (inline image), you can use a special case of attachments: set the attachment’s cid
(content ID) and refer to that cid in your HTML <img src="cid:...">
tag. This way, the image is embedded in the email content rather than just attached.
Send email to multiple recipients
Nodemailer makes it simple to send an email to multiple recipients with:
- Multiple addresses in to: Provide a comma-separated list of email addresses as the
to
field (or an array of addresses). Nodemailer will send the email to all listed recipients. - CC and BCC: Use the
cc
andbcc
fields inmailOptions
to add additional recipients who should receive copies (carbon copy or blind carbon copy).
For example, to send the same email to two friends, you could change your mailOptions
accordingly:
const mailOptions = {
from: 'you@example.com',
to: 'friend1@example.com, friend2@example.com', // multiple recipients
subject: 'Hello everyone',
text: 'This email was sent to two people at once!'
};
Pro tip: If using CC or BCC, just add cc: ‘person@example.com
‘ or bcc: ‘another@example.com
‘ as needed. Keep in mind that recipients on the to
and cc
lines will see each other’s addresses, whereas bcc
recipients are hidden from other recipients.
Send email in Bun.js using email API
Instead of managing SMTP connections and transport security yourself, you can use Mailtrap email API. This can simplify sending and often provides additional features (templating, analytics, bulk sending, etc.).
Again, let’s start with basic plain-text emails.
- Import and initialize the Mailtrap client:
First, install the Mailtrap Node.js SDK in your Bun project:
bun install mailtrap
Then, import the MailtrapClient
class from the Mailtrap package and create an instance with your API token:
import { MailtrapClient } from 'mailtrap';
const TOKEN = "<YOUR_API_TOKEN_HERE>";
const SENDER_EMAIL = "no-reply@yourdomain.com";
const RECIPIENT_EMAIL = "friend@example.com";
const client = new MailtrapClient({ token: TOKEN });
Important: Make sure to add your Mailtrap API key to <YOUR_API_TOKEN_HERE>
.
With the code above, we initialize the Mailtrap client with our API token and define the sender and recipient email addresses for convenience. The sender email should be from the domain you verified with Mailtrap, and the recipient can be any valid email address.
- Send an email using the client
The Mailtrap client provides a send()
method. We pass an object describing our email (similar to mailOptions
before). For a simple plain-text email, you can use the following snippet:
const sender = { name: "My App", email: SENDER_EMAIL };
client.send({
from: sender,
to: [ { email: RECIPIENT_EMAIL } ],
subject: "Hello from Bun.js and Mailtrap!",
text: "This is a test email sent through the Mailtrap Email API."
})
.then(response => console.log("Mailtrap API response:", response))
.catch(error => console.error("Error sending email via API:", error));
Code breakdown:
- We constructed a
sender
object with a name and email. Thefrom
field in the email uses this object. - The
to
field is an array of recipient objects. Each recipient can include anemail
and, optionally aname
. In our case we send to one recipient, but you can add multiple objects to send to many recipients (see next sections). - We provide a
subject
and atext
content for the email. This is analogous to Nodemailer’s options. - The
send()
method returns a Promise, so we chain.then
and.catch
to handle success or error. On success, you’ll get a response object (for example, with an ID of the sent message and info), and on failure, an error explaining what went wrong.
And that’s it, no direct SMTP handling in your code. The Mailtrap client takes your request and communicates with Mailtrap’s email API for you.
Important: The first time you use Mailtrap’s Email API (or SMTP) in production, your sending domain must be verified and DNS records set up as per Mailtrap’s instructions; otherwise, the API will refuse to send.
For your convenience, here is the complete index.ts code for plain-text email sending:
import { MailtrapClient } from "mailtrap";
const TOKEN = "<YOUR_API_TOKEN_HERE>";
const SENDER_EMAIL = "no-reply@yourdomain.com";
const RECIPIENT_EMAIL = "friend@example.com";
const client = new MailtrapClient({ token: TOKEN });
const sender = { name: "My App", email: SENDER_EMAIL };
client
.send({
from: sender,
to: [{ email: RECIPIENT_EMAIL }],
subject: "Hello from Bun.js and Mailtrap!",
text: "This is a test email sent through the Mailtrap Email API.",
})
.then((response) => console.log("Mailtrap API response:", response))
.catch((error) => console.error("Error sending email via API:", error));
To run the code, again, you can use bun run index.ts
.
Send HTML email
Sending an HTML email via the Mailtrap API is straightforward as well. Instead of a text
field (or in addition to it), you provide an html
field in the payload. You can also include other metadata like categories or custom variables, which Mailtrap supports for tracking and templates.
Here’s an example of sending an HTML email using the Mailtrap client (you can update your code according to it:
client.send({
from: { name: "My App", email: SENDER_EMAIL },
to: [ { email: RECIPIENT_EMAIL } ],
subject: "Welcome to My App!",
html: `
<!doctype html>
<html>
<head>
<meta charset="UTF-8">
</head>
<body style="font-family: sans-serif;">
<div style="max-width: 600px; margin: auto;">
<h1 style="font-size: 18px;">🎉 Welcome to My App!</h1>
<p>We're excited to have you on board. This is a <b>HTML email</b> sent with Bun.js.</p>
<p>Now you can send emails using Mailtrap's API and Bun runtime easily.</p>
</div>
</body>
</html>
`
})
In this snippet, we build a simple HTML document with inline styles and use it as the email body. The Mailtrap API will send this content as HTML part of the email. You can include images, links, and typical HTML content, just remember not all HTML/CSS translates perfectly to email (use tables or inline CSS for complex layouts, and avoid external CSS).
Send email with attachment
With the Mailtrap client, you include an attachments array in the send()
payload. Each attachment can have a filename, the file data as content (in binary or base64 form), and optionally a disposition (e.g., “attachment” for a normal attachment or “inline” for embedded images).
For instance, if you have a PDF file’s content in memory (say you read a file or generated it on the fly as a Buffer), you could send it like so:
import { readFileSync } from "fs";
const reportPdfBuffer = readFileSync("./invoice.pdf");
client.send({
from: { name: "Reports", email: SENDER_EMAIL },
to: [ { email: RECIPIENT_EMAIL } ],
subject: "Your requested report",
text: "Please find the report attached.",
attachments: [
{
filename: "report.pdf",
content: reportPdfBuffer, // the binary content of the PDF
disposition: "attachment" // ensures it's a downloadable attachment
}
]
});
In the above, reportPdfBuffer
is a Buffer
or binary string containing the file data. The Mailtrap API will handle encoding this and delivering it as an attachment. We set disposition: "attachment"
to indicate it’s an attachment (not to be displayed inline in the email body).
Tip: You can attach multiple files by adding multiple objects in the attachments list.
Send email to multiple recipients
With the Mailtrap API client, sending to multiple recipients is just a matter of providing multiple entries in the to
array. For example:
client.send({
from: { name: "Alerts", email: SENDER_EMAIL },
to: [
{ email: "user1@example.com", name: "User One" },
{ email: "user2@example.com", name: "User Two" },
{ email: "user3@example.com", name: "User Three" }
],
subject: "System Maintenance Notification",
text: "Dear users, we'll have a scheduled maintenance at midnight."
});
This code will send one email to each of the three recipients listed. Each recipient will get their own copy of the email. Unlike listing addresses in a single string (as we did with Nodemailer), here we provide an array of objects. This allows you to include names and other metadata per recipient.
Mailtrap email API also supports CC and BCC. The client’s send method accepts cc
and bcc
fields, which would be arrays of recipient objects just like to. For example, you could add:
cc: [ { email: "manager@example.com", name: "Manager" } ],
bcc: [ { email: "audit@example.com" } ],
Note on bulk emails: If you need to send a bulk email (a large number of recipients, like a newsletter blast), Mailtrap’s API has specialized endpoints/streams for bulk sending. You might not want to list thousands of addresses in one API call. Instead, you’d use their bulk send capability or send in batches. But for up to dozens of recipients, adding them in the to (and cc, bcc) fields is fine.
Wrapping up
That’s it for our ‘bun.js send email tutorial’!
To summarize: If you want a straightforward but minimalistic solution to send emails from Bun.js, use Nodemailer + Mailtrap SMTP. To automate your sending and use features like templates, webhooks, or even contact management, use Mailtrap Email API.
Also, be sure to check out our blog, where you can learn how to send emails in: