Skip to main content

List headers

Mailing lists use special RFC 2369 List-* headers (such as List-Help, List-Unsubscribe, and others) to help email clients display useful actions like "Unsubscribe" buttons. Instead of manually constructing these headers using the custom headers option, you can use Nodemailer's list option to define them in a simple, declarative way.

How it works​

Add a list object to your transporter.sendMail() call. Each property name in this object corresponds to a List-* header. The property names are case-insensitive, so help creates a List-Help header, unsubscribe creates List-Unsubscribe, and so on.

Value formats​

Value typeResult
stringA single URL. Nodemailer automatically wraps it in angle brackets (<...>) and adds mailto: if needed.
{ url, comment }A URL with an optional human-readable comment displayed after it.
Array< string | { url, comment } >Multiple separate header lines for the same List-* type.
Nested array (Array<Array<...>>)Multiple URLs combined into a single header line, separated by commas.
URL handling

Nodemailer automatically formats URLs for you:

  • Email addresses like admin@example.com become <mailto:admin@example.com>
  • URLs with an http:, https:, mailto:, or ftp: scheme are wrapped in angle brackets as-is
  • Other strings (including bare hostnames like ftp.example.com) are treated as domains and prefixed with http://

Comments containing non-ASCII characters are automatically encoded for email compatibility.

List-ID is formatted differently​

RFC 2919 gives List-ID its own syntax: an optional quoted phrase followed by a bare list identifier in angle brackets, rather than the URL-and-parenthesised-comment shape of the other List-* headers. Nodemailer special-cases the id key to match, stripping any scheme you pass and moving the comment in front of the identifier:

list: {
// List-ID: "My List" <list.example.com>
id: { url: "list.example.com", comment: "My List" },
}
InputGenerated header
id: 'list.example.com'List-ID: <list.example.com>
id: { url: 'list.example.com', comment: 'My List' }List-ID: "My List" <list.example.com>
id: { url: 'http://list.example.com' }List-ID: <list.example.com>

Compare this with any other key, where the same input keeps the scheme and appends the comment in parentheses, for example List-Unsubscribe: <http://list.example.com> (My List).

Complete example​

const nodemailer = require("nodemailer");

// 1. Create a transport (replace with your configuration)
const transporter = nodemailer.createTransport({
host: "smtp.example.com",
port: 587,
auth: {
user: "username",
pass: "password",
},
});

// 2. Send a message with various List-* headers
async function sendListMessage() {
await transporter.sendMail({
from: "sender@example.com",
to: "recipient@example.com",
subject: "List Message",
text: "I hope no one unsubscribes from this list!",
list: {
// List-Help: <mailto:admin@example.com?subject=help>
help: "admin@example.com?subject=help",

// List-Unsubscribe: <http://example.com> (Comment)
unsubscribe: {
url: "http://example.com",
comment: "Comment",
},

// Two separate List-Subscribe header lines:
// List-Subscribe: <mailto:admin@example.com?subject=subscribe>
// List-Subscribe: <http://example.com> (Subscribe)
subscribe: [
"admin@example.com?subject=subscribe",
{
url: "http://example.com",
comment: "Subscribe",
},
],

// Multiple URLs in a single List-Post header line:
// List-Post: <http://example.com/post>, <mailto:admin@example.com?subject=post> (Post)
post: [
[
"http://example.com/post",
{
url: "admin@example.com?subject=post",
comment: "Post",
},
],
],
},
});

console.log("List message sent");
}

sendListMessage().catch(console.error);

Resulting headers​

The example above produces these email headers:

List-Help: <mailto:admin@example.com?subject=help>
List-Unsubscribe: <http://example.com> (Comment)
List-Subscribe: <mailto:admin@example.com?subject=subscribe>
List-Subscribe: <http://example.com> (Subscribe)
List-Post: <http://example.com/post>, <mailto:admin@example.com?subject=post> (Post)

Long header lines may be physically folded onto continuation lines in the generated message; this does not change their meaning.

See Also​