;
+ transporter = nodemailer.createTransport(smtpConfig);
+
+ let transporterDefault: SMTPTransport.Options;
+ transporterDefault = transporter._defaults;
+
+ return transporter;
+}
+
+// 3. Message configuration
+
+// Commmon fields
+
+function message_common_fields_test() {
+ const message: Mail.Options = {
+ from: "sender@server.com",
+ to: "receiver@sender.com",
+ subject: "Message title",
+ text: "Plaintext version of the message",
+ html: "HTML version of the message
",
+ };
+}
+
+// Array variant of common fields
+
+function message_common_fields_array_test() {
+ const message: Mail.Options = {
+ from: ["sender@server.com", { address: "sender2@server.com", name: "Sender2" }],
+ to: ["receiver@sender.com", { address: "receiver2@sender.com", name: "Receiver2" }],
+ cc: ["ccdreceiver@sender.com"],
+ bcc: ["bccdreceiver@sender.com"],
+ };
+}
+
+// More advanced fields
+
+function message_more_advanced_fields_test() {
+ const message: Mail.Options = {
+ headers: {
+ "My-Custom-Header": "header value",
+ },
+ date: new Date("2000-01-01 00:00:00"),
+ };
+
+ const htmlstream = fs.createReadStream("content.html");
+ let transporter: nodemailer.Transporter;
+ transporter = nodemailer.createTransport();
+
+ let transporterDefault: SMTPTransport.Options;
+ transporterDefault = transporter._defaults;
+
+ transporter.sendMail({ html: htmlstream }, (err, info) => {
+ err satisfies Error | null;
+ info satisfies SMTPTransport.SentMessageInfo;
+ // @ts-expect-error - info is `SMTPTransport.SentMessageInfo`.
+ info satisfies SMTPPool.SentMessageInfo;
+ });
+}
+
+// 3. Attachments
+
+function message_attachments_test() {
+ const message: Mail.Options = {
+ attachments: [
+ {
+ // utf-8 string as an attachment
+ filename: "text1.txt",
+ content: "hello world!",
+ },
+ {
+ // binary buffer as an attachment
+ filename: "text2.txt",
+ content: new Buffer("hello world!", "utf-8"),
+ },
+ {
+ // file on disk as an attachment
+ filename: "text3.txt",
+ path: "/path/to/file.txt", // stream this file
+ },
+ {
+ // filename and content type is derived from path
+ path: "/path/to/file.txt",
+ },
+ {
+ // stream as an attachment
+ filename: "text4.txt",
+ content: fs.createReadStream("file.txt"),
+ contentTransferEncoding: "quoted-printable",
+ },
+ {
+ // define custom content type for the attachment
+ filename: "text.bin",
+ content: "hello world!",
+ contentType: "text/plain",
+ contentTransferEncoding: "7bit",
+ contentDisposition: "attachment",
+ },
+ {
+ // use URL as an attachment
+ filename: "license.txt",
+ path: "https://raw.github.com/nodemailer/nodemailer/master/LICENSE",
+ },
+ {
+ // encoded string as an attachment
+ filename: "text1.txt",
+ content: "aGVsbG8gd29ybGQh",
+ encoding: "base64",
+ contentTransferEncoding: "base64",
+ },
+ {
+ // data uri as an attachment
+ path: "data:text/plain;base64,aGVsbG8gd29ybGQ=",
+ contentDisposition: "inline",
+ contentTransferEncoding: false,
+ },
+ {
+ // use pregenerated MIME node
+ raw: "Content-Type: text/plain\r\n" // tslint:disable-line prefer-template
+ + "Content-Disposition: attachment;\r\n"
+ + "\r\n"
+ + "Hello world!",
+ },
+ ],
+ };
+}
+
+// 3. Alternatives
+
+function message_alternatives_test() {
+ const message: Mail.Options = {
+ html: "Hello world!",
+ alternatives: [
+ {
+ contentType: "text/x-web-markdown",
+ content: "**Hello world!**",
+ },
+ ],
+ };
+}
+
+// 3. Address object
+
+function message_address_object_test() {
+ const message: Mail.Options = {
+ to: "foobar@blurdybloop.com, \"Ноде Майлер\" , \"Name, User\" ",
+ cc: ["foobar@blurdybloop.com", "\"Ноде Майлер\" ", "\"Name, User\" "],
+ bcc: [
+ "foobar@blurdybloop.com",
+ {
+ name: "Майлер, Ноде",
+ address: "foobar@blurdybloop.com",
+ },
+ ],
+ };
+}
+
+// 3. Calendar events
+
+// Send a REQUEST event as a string
+
+function message_calendar_request_test() {
+ const content = "BEGIN:VCALENDAR\r\nPRODID:-//ACME/DesktopCalendar//EN\r\nMETHOD:REQUEST\r\n...";
+
+ const message: Mail.Options = {
+ from: "sender@example.com",
+ to: "recipient@example.com",
+ subject: "Appointment",
+ text: "Please see the attached appointment",
+ icalEvent: {
+ filename: "invitation.ics",
+ method: "request",
+ content,
+ },
+ };
+}
+
+// Send a PUBLISH event from a file
+
+function message_calendar_publish_test() {
+ const message: Mail.Options = {
+ from: "sender@example.com",
+ to: "recipient@example.com",
+ subject: "Appointment",
+ text: "Please see the attached appointment",
+ icalEvent: {
+ method: "PUBLISH",
+ path: "/path/to/file",
+ },
+ };
+}
+
+// Send a CANCEL event from an URL
+
+function message_calendar_cancel_test() {
+ const message: Mail.Options = {
+ from: "sender@example.com",
+ to: "recipient@example.com",
+ subject: "Appointment",
+ text: "Please see the attached appointment",
+ icalEvent: {
+ method: "CANCEL",
+ href: "http://www.example.com/events?event=123",
+ },
+ };
+}
+
+// 3. Embedded images
+
+function message_embedded_images_test() {
+ const message: Mail.Options = {
+ html: "Embedded image:
",
+ attachments: [
+ {
+ filename: "image.png",
+ path: "/path/to/file",
+ cid: "unique@nodemailer.com", // same cid value as in the html img src
+ },
+ ],
+ };
+}
+
+// 3. List headers
+
+// Setup different List-* headers
+
+function message_list_headers_test() {
+ const message: Mail.Options = {
+ from: "sender@example.com",
+ to: "recipient@example.com",
+ subject: "List Message",
+ text: "I hope no-one unsubscribes from this list!",
+ list: {
+ // List-Help:
+ help: "admin@example.com?subject=help",
+ // List-Unsubscribe: (Comment)
+ unsubscribe: {
+ url: "http://example.com",
+ comment: "Comment",
+ },
+ // List-Subscribe:
+ // List-Subscribe: (Subscribe)
+ subscribe: [
+ "admin@example.com?subject=subscribe",
+ {
+ url: "http://example.com",
+ comment: "Subscribe",
+ },
+ ],
+ // List-Post: , (Post)
+ post: [
+ [
+ "http://example.com/post",
+ {
+ url: "admin@example.com?subject=post",
+ comment: "Post",
+ },
+ ],
+ ],
+ },
+ };
+}
+
+// 3. Custom headers
+
+// Set custom headers
+
+function message_custom_headers_test() {
+ const message: Mail.Options = {
+ headers: {
+ "x-my-key": "header value",
+ "x-another-key": "another value",
+ },
+ };
+}
+
+// Multiple rows with the same key
+
+function message_multiple_rows_with_the_same_key_test() {
+ const message: Mail.Options = {
+ headers: {
+ "x-my-key": ["value for row 1", "value for row 2", "value for row 3"],
+ },
+ };
+}
+
+// Prepared headers
+
+function message_prepared_headers_test() {
+ const message: Mail.Options = {
+ headers: {
+ "x-processed": "a really long header or value with non-ascii characters 👮",
+ "x-unprocessed": {
+ prepared: true,
+ value: "a really long header or value with non-ascii characters 👮",
+ },
+ },
+ };
+}
+
+// 3. Custom source
+
+// Use string as a message body
+
+function message_string_body_test() {
+ const message: Mail.Options = {
+ envelope: {
+ from: "sender@example.com",
+ to: ["recipient@example.com"],
+ },
+ raw: `From: sender@example.com
+To: recipient@example.com
+Subject: test message
+
+Hello world!`,
+ };
+}
+
+// Set EML file as message body
+
+function message_eml_file_test() {
+ const message: Mail.Options = {
+ envelope: {
+ from: "sender@example.com",
+ to: ["recipient@example.com"],
+ },
+ raw: {
+ path: "/path/to/message.eml",
+ },
+ };
+}
+
+// Set string as attachment body
+
+function message_string_attachment_test() {
+ const message: Mail.Options = {
+ from: "sender@example.com",
+ to: "recipient@example.com",
+ subject: "Custom attachment",
+ attachments: [
+ {
+ raw: `Content-Type: text/plain
+Content-Disposition: attachment
+
+Attached text file`,
+ },
+ ],
+ };
+}
+
+// xMailer
+
+function message_xmailer_false_test() {
+ const message: Mail.Options = {
+ xMailer: false,
+ };
+}
+
+function message_xmailer_string_test() {
+ const message: Mail.Options = {
+ xMailer: "foobar",
+ };
+}
+
+// 4. SMTP transport
+
+// Single connection
+
+function smtp_single_connection_test() {
+ const smtpConfig: SMTPTransport.Options = {
+ host: "smtp.example.com",
+ port: 587,
+ secure: false, // upgrade later with STARTTLS
+ auth: {
+ user: "username",
+ pass: "password",
+ },
+ };
+ let transporter: nodemailer.Transporter;
+ transporter = nodemailer.createTransport(smtpConfig);
+
+ let transporterDefault: SMTPTransport.Options;
+ transporterDefault = transporter._defaults;
+}
+
+// Pooled connection
+
+function smtp_pooled_connection_test() {
+ const smtpConfig: SMTPPool.Options = {
+ pool: true,
+ host: "smtp.example.com",
+ port: 465,
+ secure: true, // use TLS
+ auth: {
+ user: "username",
+ pass: "password",
+ },
+ };
+ let transporter: nodemailer.Transporter;
+ transporter = nodemailer.createTransport(smtpConfig);
+
+ let transporterDefault: SMTPPool.Options;
+ transporterDefault = transporter._defaults;
+}
+
+// Allow self-signed certificates
+
+function smtp_self_signed_test() {
+ const smtpConfig: SMTPTransport.Options = {
+ host: "my.smtp.host",
+ port: 465,
+ secure: true, // use TLS
+ auth: {
+ user: "username",
+ pass: "pass",
+ },
+ tls: {
+ // do not fail on invalid certs
+ rejectUnauthorized: false,
+ },
+ };
+ let transporter: nodemailer.Transporter;
+ transporter = nodemailer.createTransport(smtpConfig);
+
+ let transporterDefault: SMTPTransport.Options;
+ transporterDefault = transporter._defaults;
+}
+
+// Verify SMTP connection configuration
+
+function smtp_verify_test() {
+ let transporter: nodemailer.Transporter;
+ transporter = nodemailer.createTransport();
+
+ let transporterDefault: SMTPTransport.Options;
+ transporterDefault = transporter._defaults;
+
+ transporter.verify((error, success) => {
+ if (error) {
+ console.log(error);
+ } else {
+ console.log("Server is ready to take our messages");
+ }
+ });
+}
+
+// 4. SMTP envelope
+
+function smtp_envelope_test() {
+ const message: Mail.Options = {
+ from: "mailer@nodemailer.com", // listed in rfc822 message header
+ to: "daemon@nodemailer.com", // listed in rfc822 message header
+ envelope: {
+ from: "Daemon ", // used as MAIL FROM: address for SMTP
+ to: "mailer@nodemailer.com, Mailer ", // used as RCPT TO: address for SMTP
+ },
+ };
+}
+
+// 4. Pooled SMTP
+
+// transporter.close()
+
+function smtp_pool_close_test() {
+ let transporter: nodemailer.Transporter;
+ transporter = nodemailer.createTransport({ pool: true });
+
+ let transporterDefault: SMTPPool.Options;
+ transporterDefault = transporter._defaults;
+
+ transporter.close();
+}
+
+// Event:‘idle’
+
+function smtp_pool_idle_test() {
+ const messages = [{ raw: "list of messages" }];
+ let transporter: nodemailer.Transporter;
+ transporter = nodemailer.createTransport({ pool: true });
+
+ let transporterDefault: SMTPPool.Options;
+ transporterDefault = transporter._defaults;
+
+ transporter.on("idle", () => {
+ // send next message from the pending queue
+ while (transporter.isIdle() && messages.length) {
+ transporter.sendMail(messages.shift()!);
+ }
+ });
+}
+
+// 4. Testing SMTP
+
+// Create a testing account on the fly
+
+function smtp_test_account_test() {
+ nodemailer.createTestAccount((err, account) => {
+ if (!err) {
+ // create reusable transporter object using the default SMTP transport
+ let transporter: nodemailer.Transporter;
+ transporter = nodemailer.createTransport({
+ host: "smtp.ethereal.email",
+ port: 587,
+ secure: false, // true for 465, false for other ports
+ auth: {
+ user: account.user, // generated ethereal user
+ pass: account.pass, // generated ethereal password
+ },
+ });
+
+ let transporterDefault: SMTPTransport.Options;
+ transporterDefault = transporter._defaults;
+ }
+ });
+}
+
+// Use environment specific SMTP settings
+
+function smtp_info_test() {
+ let transporter: nodemailer.Transporter;
+ transporter = nodemailer.createTransport();
+
+ let transporterDefault: SMTPTransport.Options;
+ transporterDefault = transporter._defaults;
+
+ transporter.sendMail({}).then((info) => {
+ info satisfies SMTPTransport.SentMessageInfo;
+ // @ts-expect-error - info is `SMTPTransport.SentMessageInfo`.
+ info satisfies SMTPPool.SentMessageInfo;
+ });
+}
+
+// 4. OAuth2
+
+// Using custom token handling
+
+function oauth2_token_handling_test() {
+ let transporter: nodemailer.Transporter;
+ transporter = nodemailer.createTransport();
+
+ let transporterDefault: SMTPTransport.Options;
+ transporterDefault = transporter._defaults;
+
+ const userTokens: { [key: string]: string } = {};
+ transporter.set("oauth2_provision_cb", (user, renew, callback) => {
+ const accessToken = userTokens[user];
+ if (!accessToken) {
+ callback(new Error("Unknown user"));
+ } else {
+ callback(null, accessToken);
+ }
+ });
+}
+
+// Token update notifications
+
+function oauth2_token_update_test() {
+ let transporter: nodemailer.Transporter;
+ transporter = nodemailer.createTransport();
+
+ let transporterDefault: SMTPTransport.Options;
+ transporterDefault = transporter._defaults;
+
+ transporter.on("token", token => {
+ console.log("A new access token was generated");
+ console.log("User: %s", token.user);
+ console.log("Access Token: %s", token.accessToken);
+ console.log("Expires: %s", new Date(token.expires));
+ });
+}
+
+// Authenticate using existing token
+
+function oauth2_existing_token_test() {
+ let transporter: nodemailer.Transporter;
+ transporter = nodemailer.createTransport({
+ host: "smtp.gmail.com",
+ port: 465,
+ secure: true,
+ auth: {
+ type: "OAuth2",
+ user: "user@example.com",
+ accessToken: "ya29.Xx_XX0xxxxx-xX0X0XxXXxXxXXXxX0x",
+ },
+ });
+
+ let transporterDefault: SMTPTransport.Options;
+ transporterDefault = transporter._defaults;
+}
+
+// Custom handler
+
+function oauth2_custom_handler_test() {
+ let transporter: nodemailer.Transporter;
+ transporter = nodemailer.createTransport({
+ host: "smtp.gmail.com",
+ port: 465,
+ secure: true,
+ auth: {
+ type: "OAuth2",
+ user: "user@example.com",
+ },
+ });
+
+ let transporterDefault: SMTPTransport.Options;
+ transporterDefault = transporter._defaults;
+
+ const userTokens: { [key: string]: string } = {};
+
+ transporter.set("oauth2_provision_cb", (user, renew, callback) => {
+ const accessToken = userTokens[user];
+ if (!accessToken) {
+ callback(new Error("Unknown user"));
+ } else {
+ callback(null, accessToken);
+ }
+ });
+}
+
+// Set up 3LO authentication
+
+function oauth2_3lo_test() {
+ let transporter: nodemailer.Transporter;
+ transporter = nodemailer.createTransport({
+ host: "smtp.gmail.com",
+ port: 465,
+ secure: true,
+ auth: {
+ type: "OAuth2",
+ user: "user@example.com",
+ clientId: "000000000000-xxx0.apps.googleusercontent.com",
+ clientSecret: "XxxxxXXxX0xxxxxxxx0XXxX0",
+ refreshToken: "1/XXxXxsss-xxxXXXXXxXxx0XXXxxXXx0x00xxx",
+ accessToken: "ya29.Xx_XX0xxxxx-xX0X0XxXXxXxXXXxX0x",
+ expires: 1484314697598,
+ },
+ });
+
+ let transporterDefault: SMTPTransport.Options;
+ transporterDefault = transporter._defaults;
+}
+
+// Set up 2LO authentication
+
+function oauth2_2lo_test() {
+ let transporter: nodemailer.Transporter;
+ transporter = nodemailer.createTransport({
+ host: "smtp.gmail.com",
+ port: 465,
+ secure: true,
+ auth: {
+ type: "OAuth2",
+ user: "user@example.com",
+ clientId: "113600000000000000000",
+ clientSecret: "-----BEGIN PRIVATE KEY-----\nMIIEvgIBADANBg...",
+ accessToken: "ya29.Xx_XX0xxxxx-xX0X0XxXXxXxXXXxX0x",
+ expires: 1484314697598,
+ },
+ });
+
+ let transporterDefault: SMTPTransport.Options;
+ transporterDefault = transporter._defaults;
+}
+
+// Provide authentication details with message options
+
+function oauth2_message_options_test() {
+ let transporter: nodemailer.Transporter;
+ transporter = nodemailer.createTransport({
+ host: "smtp.gmail.com",
+ port: 465,
+ secure: true,
+ auth: {
+ type: "OAuth2",
+ clientId: "000000000000-xxx.apps.googleusercontent.com",
+ clientSecret: "XxxxxXXxX0xxxxxxxx0XXxX0",
+ },
+ });
+
+ let transporterDefault: SMTPTransport.Options;
+ transporterDefault = transporter._defaults;
+
+ const auth: SMTPConnection.AuthenticationTypeOAuth2 = {
+ user: "user@example.com",
+ refreshToken: "1/XXxXxsss-xxxXXXXXxXxx0XXXxxXXx0x00xxx",
+ accessToken: "ya29.Xx_XX0xxxxx-xX0X0XxXXxXxXXXxX0x",
+ expires: 1484314697598,
+ };
+
+ const options: SMTPTransport.MailOptions = {
+ from: "sender@example.com",
+ to: "recipient@example.com",
+ subject: "Message",
+ text: "I hope this message gets through!",
+ auth: {
+ user: "user@example.com",
+ refreshToken: "1/XXxXxsss-xxxXXXXXxXxx0XXXxxXXx0x00xxx",
+ accessToken: "ya29.Xx_XX0xxxxx-xX0X0XxXXxXxXXXxX0x",
+ expires: 1484314697598,
+ },
+ };
+
+ transporter.sendMail(options);
+}
+
+function oauth2_privision_cb_test() {
+ let transporter: nodemailer.Transporter;
+ transporter = nodemailer.createTransport({
+ host: "smtp.gmail.com",
+ port: 465,
+ secure: true,
+ auth: {
+ type: "OAuth2",
+ },
+ });
+
+ let transporterDefault: SMTPTransport.Options;
+ transporterDefault = transporter._defaults;
+
+ const userTokens: { [key: string]: string } = {};
+
+ transporter.set("oauth2_provision_cb", (user, renew, callback) => {
+ const accessToken = userTokens[user];
+ if (!accessToken) {
+ callback(new Error("Unknown user"));
+ } else {
+ callback(null, accessToken);
+ }
+ });
+
+ const options: SMTPTransport.MailOptions = {
+ from: "sender@example.com",
+ to: "recipient@example.com",
+ subject: "Message",
+ text: "I hope this message gets through!",
+ auth: {
+ user: "user@example.com",
+ },
+ };
+
+ transporter.sendMail(options);
+}
+
+// Set up XOAuth2 authentication
+
+function oauth2_xoauth2_test() {
+ const xoauth2 = new XOAuth2({
+ user: "test@example.com",
+ clientId: "{Client ID}",
+ clientSecret: "{Client Secret}",
+ refreshToken: "saladus",
+ accessUrl: "http://localhost:8993/",
+ accessToken: "abc",
+ timeout: 3600,
+ });
+ let transporter: nodemailer.Transporter;
+ transporter = nodemailer.createTransport({
+ service: "gmail",
+ auth: {
+ type: "OAUTH2",
+ user: "user@example.com",
+ oauth2: xoauth2,
+ method: "XOAUTH2",
+ },
+ });
+
+ let transporterDefault: SMTPTransport.Options;
+ transporterDefault = transporter._defaults;
+}
+
+// Set up custom authentication
+
+async function custom_auth_async_test() {
+ const account = await nodemailer.createTestAccount();
+
+ let transporter: nodemailer.Transporter;
+ transporter = nodemailer.createTransport(
+ {
+ host: account.smtp.host,
+ port: account.smtp.port,
+ secure: account.smtp.secure,
+ auth: {
+ type: "custom",
+
+ user: account.user,
+ pass: account.pass,
+
+ method: "x-login",
+ },
+ logger: false,
+ debug: false,
+
+ customAuth: {
+ // can create multiple handlers
+ "x-login": async ctx => {
+ // This custom method implements AUTH LOGIN even though Nodemailer supports it natively.
+ // AUTH LOGIN mechanism includes multiple steps, so it's great for a demo nevertheless
+
+ console.log("Performing custom authentication for %s", ctx.auth.credentials.user);
+ console.log("Supported extensions: %s", ctx.extensions.join(", "));
+ console.log("Supported auth methods: %s", ctx.authMethods.join(", "));
+
+ if (ctx.authMethods.indexOf("LOGIN") === -1) {
+ console.log("Server does not support AUTH LOGIN");
+ throw new Error("Can not log in");
+ }
+ console.log("AUTH LOGIN is supported, proceeding with login...");
+
+ let cmd;
+
+ cmd = await ctx.sendCommand("AUTH LOGIN");
+ if (cmd.status !== 334) {
+ // expecting '334 VXNlcm5hbWU6'
+ throw new Error("Invalid login sequence while waiting for \"334 VXNlcm5hbWU6\"");
+ }
+
+ console.log("Sending username: %s", ctx.auth.credentials.user);
+ cmd = await ctx.sendCommand(Buffer.from(ctx.auth.credentials.user, "utf-8").toString("base64"));
+ if (cmd.status !== 334) {
+ // expecting '334 UGFzc3dvcmQ6'
+ throw new Error("Invalid login sequence while waiting for \"334 UGFzc3dvcmQ6\"");
+ }
+
+ console.log("Sending password: %s", "*".repeat(ctx.auth.credentials.pass.length));
+ cmd = await ctx.sendCommand(Buffer.from(ctx.auth.credentials.pass, "utf-8").toString("base64"));
+ if (cmd.status < 200 || cmd.status >= 300) {
+ // expecting a 235 response, just in case allow everything in 2xx range
+ throw new Error("User failed to authenticate");
+ }
+
+ console.log("User authenticated! (%s)", cmd.response);
+
+ // all checks passed
+ return true;
+ },
+ },
+ },
+ {
+ // default message fields
+
+ // sender info
+ from: "Pangalink ",
+ headers: {
+ "X-Laziness-level": "1000", // just an example header, no need to use this
+ },
+ },
+ );
+
+ let transporterDefault: SMTPTransport.Options;
+ transporterDefault = transporter._defaults;
+}
+
+async function custom_auth_cb_test() {
+ const account = await nodemailer.createTestAccount();
+
+ let transporter: nodemailer.Transporter;
+ transporter = nodemailer.createTransport(
+ {
+ host: account.smtp.host,
+ port: account.smtp.port,
+ secure: account.smtp.secure,
+ auth: {
+ type: "custom",
+
+ user: account.user,
+ pass: account.pass,
+
+ method: "x-login",
+ },
+ logger: false,
+ debug: false,
+
+ customAuth: {
+ // can create multiple handlers
+ "x-login": ctx => {
+ // This custom method implements AUTH LOGIN even though Nodemailer supports it natively.
+ // AUTH LOGIN mechanism includes multiple steps, so it's great for a demo nevertheless
+
+ console.log("Performing custom authentication for %s", ctx.auth.credentials.user);
+ console.log("Supported extensions: %s", ctx.extensions.join(", "));
+ console.log("Supported auth methods: %s", ctx.authMethods.join(", "));
+
+ if (ctx.authMethods.indexOf("LOGIN") === -1) {
+ console.log("Server does not support AUTH LOGIN");
+ return ctx.reject(new Error("Can not log in"));
+ }
+ console.log("AUTH LOGIN is supported, proceeding with login...");
+
+ ctx.sendCommand("AUTH LOGIN", (err, cmd) => {
+ if (err) {
+ return ctx.reject(err);
+ }
+
+ if (cmd.status !== 334) {
+ // expecting '334 VXNlcm5hbWU6'
+ return ctx.reject("Invalid login sequence while waiting for \"334 VXNlcm5hbWU6\"");
+ }
+
+ console.log("Sending username: %s", ctx.auth.credentials.user);
+ ctx.sendCommand(
+ Buffer.from(ctx.auth.credentials.user, "utf-8").toString("base64"),
+ (err, cmd) => {
+ if (err) {
+ return ctx.reject(err);
+ }
+ if (cmd.status !== 334) {
+ // expecting '334 UGFzc3dvcmQ6'
+ return ctx.reject("Invalid login sequence while waiting for \"334 UGFzc3dvcmQ6\"");
+ }
+
+ console.log("Sending password: %s", "*".repeat(ctx.auth.credentials.pass.length));
+ ctx.sendCommand(
+ Buffer.from(ctx.auth.credentials.pass, "utf-8").toString("base64"),
+ (err, cmd) => {
+ if (err) {
+ return ctx.reject(err);
+ }
+ if (cmd.status < 200 || cmd.status >= 300) {
+ // expecting a 235 response, just in case allow everything in 2xx range
+ return ctx.reject("User failed to authenticate");
+ }
+
+ console.log("User authenticated! (%s)", cmd.response);
+
+ // all checks passed
+ return ctx.resolve();
+ },
+ );
+ },
+ );
+ });
+ },
+ },
+ },
+ {
+ // default message fields
+
+ // sender info
+ from: "Pangalink ",
+ headers: {
+ "X-Laziness-level": "1000", // just an example header, no need to use this
+ },
+ },
+ );
+
+ let transporterDefault: SMTPTransport.Options;
+ transporterDefault = transporter._defaults;
+}
+
+// 5. Sendmail transport
+
+// Send a message using specific binary
+
+function sendmail_test() {
+ let transporter: nodemailer.Transporter;
+ transporter = nodemailer.createTransport({
+ sendmail: true,
+ newline: "unix",
+ path: "/usr/sbin/sendmail",
+ });
+
+ let transporterDefault: SendmailTransport.Options;
+ transporterDefault = transporter._defaults;
+
+ transporter.sendMail(
+ {
+ from: "sender@example.com",
+ to: "recipient@example.com",
+ subject: "Message",
+ text: "I hope this message gets delivered!",
+ },
+ (err, info) => {
+ err satisfies Error | null;
+ info satisfies SendmailTransport.SentMessageInfo;
+ // @ts-expect-error - info is `SendmailTransport.SentMessageInfo`.
+ info satisfies SMTPPool.SentMessageInfo;
+ },
+ );
+}
+
+// line ending transforms using windows-style newlines
+
+function sendmail_line_endings_windows_test() {
+ function process_le(mail: MailMessage) {
+ const input = mail.message.createReadStream();
+ input.pipe(new LeWindows());
+ }
+}
+
+// line ending transforms using unix-style newlines
+
+function sendmail_line_endings_unix_test() {
+ function process_le(mail: MailMessage) {
+ const input = mail.message.createReadStream();
+ input.pipe(new LeUnix());
+ }
+}
+
+// 5. SES transport
+
+// Send a message using SES transport
+
+function ses_test() {
+ // configure AWS SDK
+ aws.config.loadFromPath("config.json");
+
+ // create Nodemailer SES transporter
+ let transporter: nodemailer.Transporter;
+ transporter = nodemailer.createTransport({
+ SES: {
+ sesClient: new SESv2Client(),
+ SendEmailCommand,
+ },
+ component: "ses-transport",
+ });
+
+ let transporterDefault: SESTransport.Options;
+ transporterDefault = transporter._defaults;
+
+ const options: SESTransport.MailOptions = {
+ from: "sender@example.com",
+ to: "recipient@example.com",
+ subject: "Message",
+ text: "I hope this message gets sent!",
+ ses: {
+ // optional extra arguments for SendRawEmail
+ EmailTags: [
+ {
+ Name: "tag name",
+ Value: "tag value",
+ },
+ ],
+ },
+ };
+
+ // send some mail
+ transporter.sendMail(options, (err, info) => {
+ err satisfies Error | null;
+ info satisfies SESTransport.SentMessageInfo;
+ // @ts-expect-error - info is `SESTransport.SentMessageInfo`.
+ info satisfies SMTPPool.SentMessageInfo;
+ });
+}
+
+// 5. Stream transport
+
+// Stream a message with windows-style newlines
+
+function stream_test() {
+ let transporter: nodemailer.Transporter;
+ transporter = nodemailer.createTransport({
+ streamTransport: true,
+ newline: "windows",
+ });
+
+ let transporterDefault: StreamTransport.Options;
+ transporterDefault = transporter._defaults;
+
+ transporter.sendMail(
+ {
+ from: "sender@example.com",
+ to: "recipient@example.com",
+ subject: "Message",
+ text: "I hope this message gets streamed!",
+ },
+ (err, info) => {
+ err satisfies Error | null;
+ info satisfies StreamTransport.SentMessageInfo;
+ // @ts-expect-error - info is `StreamTransport.SentMessageInfo`.
+ info satisfies SMTPPool.SentMessageInfo;
+ },
+ );
+}
+
+// Create a buffer with unix-style newlines
+
+function stream_buffer_unix_newlines_test() {
+ let transporter: nodemailer.Transporter;
+ transporter = nodemailer.createTransport({
+ streamTransport: true,
+ newline: "unix",
+ buffer: true,
+ normalizeHeaderKey: key => key.toUpperCase(),
+ });
+
+ let transporterDefault: StreamTransport.Options;
+ transporterDefault = transporter._defaults;
+
+ transporter.sendMail(
+ {
+ from: "sender@example.com",
+ to: "recipient@example.com",
+ subject: "Message",
+ text: "I hope this message gets buffered!",
+ },
+ (err, info) => {
+ err satisfies Error | null;
+ info satisfies StreamTransport.SentMessageInfo;
+ // @ts-expect-error - info is `StreamTransport.SentMessageInfo`.
+ info satisfies SMTPPool.SentMessageInfo;
+ },
+ );
+}
+
+// Create a JSON encoded message object
+
+function json_test() {
+ let transporter: nodemailer.Transporter;
+ transporter = nodemailer.createTransport({
+ jsonTransport: true,
+ skipEncoding: true,
+ });
+
+ let transporterDefault: JSONTransport.Options;
+ transporterDefault = transporter._defaults;
+
+ transporter.sendMail(
+ {
+ from: "sender@example.com",
+ to: "recipient@example.com",
+ subject: "Message",
+ text: "I hope this message gets buffered!",
+ },
+ (err, info) => {
+ err satisfies Error | null;
+ info satisfies JSONTransport.SentMessageInfo;
+ // @ts-expect-error - info is `JSONTransport.SentMessageInfo`.
+ info satisfies SMTPPool.SentMessageInfo;
+ },
+ );
+}
+
+// 6. Create plugins
+
+// 'compile'
+
+function plugin_compile_test() {
+ let transporter: nodemailer.Transporter;
+ transporter = nodemailer.createTransport();
+
+ let transporterDefault: SMTPTransport.Options;
+ transporterDefault = transporter._defaults;
+
+ function plugin(mail: typeof transporter.MailMessage, callback: (err?: Error | null) => void) {
+ // if mail.data.html is a file or an url, it is returned as a Buffer
+ mail.resolveContent(mail.data, "html", (err, html) => {
+ if (err) {
+ callback(err);
+ return;
+ }
+ console.log("HTML contents: %s", html.toString());
+ callback();
+ });
+ }
+
+ transporter.use("compile", (mail, callback) => {
+ if (!mail.data.text && mail.data.html && typeof mail.data.html === "string") {
+ mail.data.text = mail.data.html.replace(/<[^>]*>/g, " ");
+ }
+ callback();
+ });
+}
+
+// 'stream'
+
+function plugin_stream_test() {
+ const Transform = require("stream").Transform;
+ const transformer: stream.Transform = new Transform();
+
+ transformer._transform = function transform(chunk: Buffer, encoding, done) {
+ // replace all tabs with spaces in the stream chunk
+ for (let i = 0; i < chunk.length; i++) {
+ if (chunk[i] === 0x09) {
+ chunk[i] = 0x20;
+ }
+ }
+ this.push(chunk);
+ done();
+ };
+
+ let transporter: nodemailer.Transporter;
+ transporter = nodemailer.createTransport();
+
+ let transporterDefault: SMTPTransport.Options;
+ transporterDefault = transporter._defaults;
+
+ transporter.use("stream", (mail, callback) => {
+ // apply output transformer to the raw message stream
+ mail.message.transform(transformer);
+ callback();
+ });
+
+ transporter.use("stream", (mail, callback) => {
+ const addresses = mail.message.getAddresses();
+ console.log("From: %s", JSON.stringify(addresses.from));
+ console.log("To: %s", JSON.stringify(addresses.to));
+ console.log("Cc: %s", JSON.stringify(addresses.cc));
+ console.log("Bcc: %s", JSON.stringify(addresses.bcc));
+ callback();
+ });
+}
+
+// Transport Example
+
+function plugin_transport_example_test() {
+ interface MailOptions extends Mail.Options {
+ mailOption?: "foo" | undefined;
+ }
+ interface Options extends MailOptions, nodemailer.TransportOptions {
+ transportOptions: "bar";
+ }
+
+ interface TestTransportInfo {
+ messageId: string;
+ }
+ class Transport implements nodemailer.Transport {
+ name = "minimal";
+ version = "0.1.0";
+ constructor(options: Options) {}
+ send(
+ mail: MailMessage,
+ callback: (err: Error | null, info: TestTransportInfo) => void,
+ ): void {
+ const input = mail.message.createReadStream();
+ input.pipe(process.stdout);
+ input.on("end", () => {
+ callback(null, { messageId: "baz" });
+ });
+ }
+ }
+ class AnyTransport implements nodemailer.Transport {
+ name = "minimal";
+ version = "0.1.0";
+ constructor(options: Options) {}
+ send(mail: MailMessage, callback: (err: Error | null, info: any) => void): void {
+ const input = mail.message.createReadStream();
+ input.pipe(process.stdout);
+ input.on("end", () => {
+ callback(null, { messageId: "baz" });
+ });
+ }
+ }
+
+ let transporter: nodemailer.Transporter;
+ transporter = nodemailer.createTransport(
+ new Transport({
+ transportOptions: "bar",
+ }),
+ );
+
+ let transporterDefault: SMTPTransport.Options;
+ transporterDefault = transporter._defaults;
+
+ const options: MailOptions = {
+ from: "sender",
+ to: "receiver",
+ subject: "hello",
+ text: "hello world!",
+ mailOption: "foo",
+ };
+
+ transporter.sendMail(options);
+}
+
+// 7. https://nodemailer.com/dkim/
+
+// Sign all messages
+
+function dkim_sign_all_test() {
+ const opts: SMTPTransport.Options = {
+ host: "smtp.example.com",
+ port: 465,
+ secure: true,
+ dkim: {
+ domainName: "example.com",
+ keySelector: "2017",
+ privateKey: "-----BEGIN PRIVATE KEY-----\nMIIEvgIBADANBg...",
+ },
+ };
+}
+
+// Sign all messages with multiple keys
+
+function dkim_sign_multiple_keys_test() {
+ let transporter: nodemailer.Transporter;
+ transporter = nodemailer.createTransport({
+ host: "smtp.example.com",
+ port: 465,
+ secure: true,
+ dkim: {
+ keys: [
+ {
+ domainName: "example.com",
+ keySelector: "2017",
+ privateKey: "-----BEGIN PRIVATE KEY-----\nMIIEvgIBADANBg...",
+ },
+ {
+ domainName: "example.com",
+ keySelector: "2016",
+ privateKey: "-----BEGIN PRIVATE KEY-----\nMIIEvgIBADANBg...",
+ },
+ ],
+ cacheDir: false,
+ },
+ });
+
+ let transporterDefault: SMTPTransport.Options;
+ transporterDefault = transporter._defaults;
+}
+
+// Sign a specific message
+
+function dkim_sign_specific_message_test() {
+ let transporter: nodemailer.Transporter;
+ transporter = nodemailer.createTransport({
+ host: "smtp.example.com",
+ port: 465,
+ secure: true,
+ });
+
+ let transporterDefault: SMTPTransport.Options;
+ transporterDefault = transporter._defaults;
+
+ const message: Mail.Options = {
+ from: "sender@example.com",
+ to: "recipient@example.com",
+ subject: "Message",
+ text: "I hope this message gets read!",
+ dkim: {
+ domainName: "example.com",
+ keySelector: "2017",
+ privateKey: "-----BEGIN PRIVATE KEY-----\nMIIEvgIBADANBg...",
+ },
+ };
+}
+
+// Cache large messages for signing
+
+function dkim_cache_large_messages_test() {
+ let transporter: nodemailer.Transporter;
+ transporter = nodemailer.createTransport({
+ host: "smtp.example.com",
+ port: 465,
+ secure: true,
+ dkim: {
+ domainName: "example.com",
+ keySelector: "2017",
+ privateKey: "-----BEGIN PRIVATE KEY-----\nMIIEvgIBADANBg...",
+ cacheDir: "/tmp",
+ cacheTreshold: 100 * 1024,
+ },
+ });
+
+ let transporterDefault: SMTPTransport.Options;
+ transporterDefault = transporter._defaults;
+}
+
+// Do not sign specific header keys
+
+function dkim_specific_header_key_test() {
+ let transporter: nodemailer.Transporter;
+ transporter = nodemailer.createTransport({
+ host: "smtp.example.com",
+ port: 465,
+ secure: true,
+ dkim: {
+ domainName: "example.com",
+ keySelector: "2017",
+ privateKey: "-----BEGIN PRIVATE KEY-----\nMIIEvgIBADANBg...",
+ skipFields: "message-id:date",
+ },
+ });
+
+ let transporterDefault: SMTPTransport.Options;
+ transporterDefault = transporter._defaults;
+}
+
+// 8. SMTP Connection
+
+// SMTP Connection
+
+function smtp_connection_test() {
+ const connection = new SMTPConnection({ secure: true, secured: true });
+ connection.connect(err => {
+ if (err) throw err;
+ connection.login({ user: "user", pass: "pass" }, err => {
+ if (err) throw err;
+ connection.send({ from: "a@example.com", to: "b@example.net" }, "message", (err, info) => {
+ if (err) {
+ const code: string = err.code || "???";
+ const response: string = err.response || "???";
+ const responseCode: number = err.responseCode || 0;
+ const command: string = err.command || "???";
+ throw err;
+ }
+ connection.reset(() => {
+ if (err) throw err;
+ connection.quit();
+ connection.close();
+ });
+ });
+ });
+ });
+}
+
+// LMTP Connection
+
+function lmtp_connection_test() {
+ const connection = new SMTPConnection({ lmtp: true });
+ connection.connect(err => {
+ if (err) throw err;
+ connection.login({ user: "user", pass: "pass" }, err => {
+ if (err) throw err;
+ connection.send({ from: "a@example.com", to: "b@example.net" }, "message", (err, info) => {
+ if (err) {
+ const code: string = err.code || "???";
+ const response: string = err.response || "???";
+ const responseCode: number = err.responseCode || 0;
+ const command: string = err.command || "???";
+ throw err;
+ }
+ connection.reset(() => {
+ if (err) throw err;
+ connection.quit();
+ connection.close();
+ });
+ });
+ });
+ });
+}
+
+// Mailcomposer
+
+// createReadStream
+
+function mailcomposer_createReadStream_test() {
+ const mail = new MailComposer({ from: "..." });
+ const stream = mail.compile().createReadStream();
+ stream.pipe(process.stdout);
+}
+
+// build
+
+function mailcomposer_build_callback_test() {
+ const mail = new MailComposer({ from: "..." });
+ mail.compile().build((err, message) => {
+ process.stdout.write(message);
+ });
+}
+
+async function mailcomposer_build_promise_test() {
+ const mail = new MailComposer({ from: "..." });
+ const message = await mail.compile().build();
+ process.stdout.write(message);
+}
+
+// addressparser
+
+declare function isAddress(arg: unknown): arg is addressparser.Address;
+
+declare function isGroup(arg: unknown): arg is addressparser.Group;
+
+function addressparser_test() {
+ const input = "andris@tr.ee";
+ const results: addressparser.AddressOrGroup[] = addressparser(input);
+ const firstResult = results[0];
+ if (isAddress(firstResult)) {
+ const address: string = firstResult.address;
+ const name: string = firstResult.name;
+ } else if (isGroup(firstResult)) {
+ const group: addressparser.Address[] = firstResult.group;
+ const name: string = firstResult.name;
+ }
+}
+
+function addressparser_flatten_test() {
+ const input = "andris@tr.ee";
+ const results = addressparser(input, { flatten: true });
+ const firstResult = results[0];
+ const address: string = firstResult.address;
+ const name: string = firstResult.name;
+}
+
+// base64
+
+function base64_test() {
+ base64.encode("abcd= ÕÄÖÜ");
+
+ base64.encode(new Buffer([0x00, 0x01, 0x02, 0x20, 0x03]));
+}
+
+// dkim
+
+function dkim_test_options() {
+ const dkim = new DKIM({
+ domainName: "example.com",
+ keySelector: "2017",
+ privateKey: "-----BEGIN PRIVATE KEY-----\nMIIEvgIBADANBg...",
+ });
+ const stream = dkim.sign("Message");
+ stream.pipe(process.stdout);
+}
+
+function dkim_test_extra_options() {
+ const dkim = new DKIM();
+ const stream = dkim.sign("Message", {
+ domainName: "example.com",
+ keySelector: "2017",
+ privateKey: "-----BEGIN PRIVATE KEY-----\nMIIEvgIBADANBg...",
+ });
+ stream.pipe(process.stdout);
+}
+
+// fetch
+
+function fetch_test() {
+ const stream = fetch("http://localhost/");
+
+ const statusCode: number = stream.statusCode;
+ const headers = stream.headers;
+ const contentType: string | undefined = headers["content-type"];
+
+ fetch("http://localhost:/", {
+ allowErrorResponse: true,
+ method: "post",
+ cookie: "test=pest",
+ body: {
+ hello: "world 😭",
+ another: "value",
+ },
+ timeout: 1000,
+ tls: {
+ rejectUnauthorized: true,
+ },
+ });
+}
+
+// fetch/cookies
+
+function fetch_cookies_test() {
+ const biskviit = new Cookies();
+
+ biskviit.getPath("/");
+
+ biskviit.isExpired({
+ name: "a",
+ value: "b",
+ expires: new Date(Date.now() + 10000),
+ });
+
+ biskviit.compare(
+ {
+ name: "zzz",
+ path: "/",
+ domain: "example.com",
+ secure: false,
+ httponly: false,
+ },
+ {
+ name: "zzz",
+ path: "/",
+ domain: "example.com",
+ secure: false,
+ httponly: false,
+ },
+ );
+
+ biskviit.add({
+ name: "zzz",
+ value: "abc",
+ path: "/",
+ expires: new Date(Date.now() + 10000),
+ domain: "example.com",
+ secure: false,
+ httponly: false,
+ });
+
+ const cookie = {
+ name: "zzz",
+ value: "abc",
+ path: "/def/",
+ expires: new Date(Date.now() + 10000),
+ domain: "example.com",
+ secure: false,
+ httponly: false,
+ };
+
+ biskviit.match(cookie, "http://example.com/def/");
+
+ biskviit.parse("theme=plain");
+
+ biskviit.list("https://www.foo.com");
+
+ biskviit.get("https://www.foo.com");
+
+ biskviit.set("theme=plain", "https://foo.com/");
+}
+
+// mime-funcs
+
+function mime_funcs_test() {
+ mimeFuncs.isPlainText("abc");
+
+ mimeFuncs.hasLongerLines("abc\ndef", 5);
+
+ mimeFuncs.encodeWord("See on õhin test");
+ mimeFuncs.encodeWord("See on õhin test", "B");
+ mimeFuncs.encodeWords("метель\" вьюга", "Q", 52);
+ mimeFuncs.encodeWords("Jõgeva Jõgeva Jõgeva mugeva Jõgeva Jõgeva Jõgeva Jõgeva Jõgeva", "Q", 16);
+ mimeFuncs.encodeWords("õõõõõ õõõõõ õõõõõ mugeva õõõõõ õõõõõ õõõõõ õõõõõ Jõgeva", "B", 30);
+
+ mimeFuncs.buildHeaderParam("title", "this is just a title", 500);
+
+ const parsedHeader = mimeFuncs.parseHeaderValue("content-disposition: attachment; filename=filename");
+ console.log(parsedHeader.params.filename);
+
+ mimeFuncs.buildHeaderValue({
+ value: "test",
+ });
+
+ mimeFuncs.buildHeaderValue({
+ value: "test",
+ params: {
+ a: "b",
+ },
+ });
+
+ mimeFuncs.foldLines("Testin command line", 76, true);
+ mimeFuncs.foldLines("Testin command line", 76);
+}
+
+// mime-node
+
+function mime_node_test() {
+ let mb: MimeNode;
+
+ // constructor
+ {
+ mb = new MimeNode();
+
+ mb = new MimeNode("text/plain");
+
+ mb = new MimeNode("text/plain", {});
+
+ mb = new MimeNode("text/plain", {
+ rootNode: mb,
+ parentNode: mb,
+ filename: "filename",
+ hostname: "hostname",
+ baseBoundary: "baseBoundary",
+ keepBcc: true,
+ newline: "win",
+ normalizeHeaderKey: key => key.toUpperCase(),
+ boundaryPrefix: "boundaryPrefix",
+ disableFileAccess: true,
+ disableUrlAccess: true,
+ });
+
+ mb = new MimeNode("text/plain", { textEncoding: "B" });
+ mb = new MimeNode("text/plain", { textEncoding: "Q" });
+ }
+
+ const child = mb.createChild("multipart/mixed");
+ mb = mb.appendChild(child);
+ mb = child.replace(child);
+
+ mb = mb.setHeader("key", "value");
+
+ // $ExpectType string
+ mb.getHeader("key");
+
+ mb = mb.addHeader("key", "value1");
+ mb = mb.addHeader({
+ key: "value4",
+ key2: "value5",
+ });
+
+ mb = mb.setHeader([
+ {
+ key: "key",
+ value: "value2",
+ },
+ {
+ key: "key2",
+ value: "value3",
+ },
+ ]);
+
+ mb = mb.setHeader("key", ["value1", "value2", "value3"]);
+
+ mb = mb.setContent("abc");
+
+ // $ExpectType void
+ mb.build((err, buf) => {
+ // $ExpectType Error | null
+ err;
+ // $ExpectType Buffer || Buffer
+ buf;
+ });
+
+ // $ExpectType Promise || Promise>
+ mb.build();
+
+ // $ExpectType string
+ mb.getTransferEncoding();
+
+ // $ExpectType string
+ mb.buildHeaders();
+
+ {
+ // $ExpectType Readable
+ mb.createReadStream();
+
+ const options: stream.ReadableOptions = {};
+ // $ExpectType Readable
+ mb.createReadStream(options);
+ }
+
+ // $ExpectType void
+ mb.transform(new stream.Transform());
+
+ // $ExpectType void
+ mb.processFunc(input => {
+ // $ExpectType Readable
+ input;
+ return input;
+ });
+
+ {
+ const outputStream = new stream.Readable();
+ const options: stream.ReadableOptions = {};
+
+ // $ExpectType void
+ mb.stream(outputStream, options, err => {
+ // $ExpectType Error | null | undefined
+ err;
+ });
+ }
+
+ {
+ let envelope: Mail.Envelope = {};
+ mb = mb.setEnvelope(envelope);
+ }
+
+ {
+ const addresses = mb.getAddresses();
+
+ // $ExpectType string[] | undefined
+ addresses.bcc;
+ // $ExpectType string[] | undefined
+ addresses.cc;
+ // $ExpectType string[] | undefined
+ addresses.from;
+ // $ExpectType string[] | undefined
+ addresses["reply-to"];
+ // $ExpectType string[] | undefined
+ addresses.sender;
+ // $ExpectType string[] | undefined
+ addresses.to;
+ }
+
+ {
+ const envelope = mb.getEnvelope();
+
+ // $ExpectType string | false
+ envelope.from;
+ // $ExpectType string[]
+ envelope.to;
+ }
+
+ // $ExpectType string
+ mb.messageId();
+
+ {
+ mb = mb.setRaw("raw");
+ mb = mb.setRaw(Buffer.from(""));
+ mb = mb.setRaw(new stream.Readable());
+ }
+
+ // $ExpectType string
+ mb.baseBoundary;
+
+ // $ExpectType string | false | undefined
+ mb.boundary;
+
+ // $ExpectType string
+ mb.boundaryPrefix;
+
+ // $ExpectType MimeNode[]
+ mb.childNodes;
+
+ // $ExpectType string | Buffer | Readable | undefined || string | Buffer | Readable | undefined
+ mb.content;
+
+ // $ExpectType string | undefined
+ mb.contentType;
+
+ // $ExpectType Date
+ mb.date;
+
+ // $ExpectType boolean
+ mb.disableFileAccess;
+
+ // $ExpectType boolean
+ mb.disableUrlAccess;
+
+ // $ExpectType string | undefined
+ mb.filename;
+
+ // $ExpectType string | undefined
+ mb.hostname;
+
+ // $ExpectType boolean
+ mb.keepBcc;
+
+ // $ExpectType boolean | undefined
+ mb.multipart;
+
+ // $ExpectType string | undefined
+ mb.newline;
+
+ // $ExpectType number
+ mb.nodeCounter;
+
+ // $ExpectType ((key: string) => string) | undefined
+ mb.normalizeHeaderKey;
+
+ // $ExpectType MimeNode | undefined
+ mb.parentNode;
+
+ // $ExpectType MimeNode
+ mb.rootNode;
+
+ // $ExpectType "B" | "Q" | ""
+ mb.textEncoding;
+}
+
+// mime-types
+
+function mime_types_test() {
+ mimeTypes.detectExtension(false);
+ mimeTypes.detectExtension("unknown");
+
+ mimeTypes.detectMimeType(false);
+ mimeTypes.detectMimeType("unknown");
+}
+
+// qp
+
+function qp_test() {
+ qp.encode("abcd= ÕÄÖÜ");
+
+ qp.encode(new Buffer([0x00, 0x01, 0x02, 0x20, 0x03]));
+}
+
+// shared
+
+function shared_getLogger_test() {
+ shared.getLogger({
+ logger: false,
+ });
+
+ shared.getLogger();
+
+ const options = shared.parseConnectionUrl(
+ "smtps://user:pass@localhost:123?tls.rejectUnauthorized=false&name=horizon",
+ );
+ console.log(options.secure, options.auth!.user, options.tls!.rejectUnauthorized);
+}
+
+function shared_resolveContent_string_test() {
+ const mail = {
+ data: {
+ html: "Tere, tere
vana kere!
\n",
+ },
+ };
+
+ shared.resolveContent(mail.data, "html", (err, value) => {
+ if (!err) {
+ console.log(value);
+ }
+ });
+
+ shared.resolveContent(mail.data, "html").then(value => console.log(value));
+}
+
+function shared_resolveContent_buffer_test() {
+ const mail = {
+ data: {
+ html: new Buffer("Tere, tere
vana kere!
\n"),
+ },
+ };
+
+ shared.resolveContent(mail.data, "html", (err, value) => {
+ if (!err) {
+ console.log(value);
+ }
+ });
+
+ shared.resolveContent(mail.data, "html").then(value => console.log(value));
+}
+
+function shared_assign_test() {
+ const target = {
+ a: 1,
+ b: 2,
+ c: 3,
+ };
+ const arg1 = {
+ b: 5,
+ y: 66,
+ e: 33,
+ };
+
+ const arg2 = {
+ y: 17,
+ qq: 98,
+ };
+
+ shared.assign(target, arg1, arg2);
+}
+
+function shared_encodeXText_test() {
+ shared.encodeXText("teretere");
+}
+
+// well-known
+
+function well_known_test() {
+ const options = wellKnown("Gmail");
+ if (options) {
+ console.log(options.host, options.port, options.secure);
+ }
+}
+
+// xoauth2
+
+function xoauth2_test() {
+ const xoauth2 = new XOAuth2({
+ user: "test@example.com",
+ clientId: "{Client ID}",
+ clientSecret: "{Client Secret}",
+ refreshToken: "saladus",
+ accessUrl: "http://localhost:8993/",
+ accessToken: "abc",
+ timeout: 3600,
+ });
+ xoauth2.getToken(false, (err, accessToken) => {
+ if (err) throw err;
+ const token: string = xoauth2.buildXOAuth2Token(accessToken);
+ });
+}
+
+function xoauth2_sign_payload_test() {
+ const xoauth2 = new XOAuth2({
+ user: "test@example.com",
+ serviceClient: "{Client ID}",
+ accessUrl: "http://localhost:8497/",
+ timeout: 3600,
+ privateKey: "-----BEGIN RSA PRIVATE KEY-----\n...",
+ });
+ xoauth2.jwtSignRS256({
+ some: "payload",
+ });
+}
+
+// testSendMailOverloads
+(async () => {
+ const DISABLE_EMAILS = false;
+
+ const transporter = DISABLE_EMAILS
+ ? nodemailer.createTransport({
+ streamTransport: true,
+ buffer: true,
+ })
+ : nodemailer.createTransport({
+ host: "localhost",
+ port: 25,
+ });
+
+ await transporter.sendMail({
+ from: "sender@example.com",
+ to: "recipient@example.com",
+ subject: "Buffered message",
+ text: "This message is buffered.",
+ });
+});
diff --git a/types/nodemailer/v7/package.json b/types/nodemailer/v7/package.json
new file mode 100644
index 00000000000000..9774a4ca4d8a55
--- /dev/null
+++ b/types/nodemailer/v7/package.json
@@ -0,0 +1,30 @@
+{
+ "private": true,
+ "name": "@types/nodemailer",
+ "version": "7.0.9999",
+ "projects": [
+ "https://github.com/nodemailer/nodemailer",
+ "https://nodemailer.com"
+ ],
+ "dependencies": {
+ "@types/node": "*"
+ },
+ "devDependencies": {
+ "@aws-sdk/client-sesv2": "^3.985.0",
+ "@types/nodemailer": "workspace:."
+ },
+ "owners": [
+ {
+ "name": "Rogier Schouten",
+ "githubUsername": "rogierschouten"
+ },
+ {
+ "name": "Piotr Roszatycki",
+ "githubUsername": "dex4er"
+ },
+ {
+ "name": "Daniel Chao",
+ "githubUsername": "bioball"
+ }
+ ]
+}
diff --git a/types/nodemailer/v7/tsconfig.json b/types/nodemailer/v7/tsconfig.json
new file mode 100644
index 00000000000000..9781d783310670
--- /dev/null
+++ b/types/nodemailer/v7/tsconfig.json
@@ -0,0 +1,50 @@
+{
+ "compilerOptions": {
+ "module": "node16",
+ "lib": [
+ "es6"
+ ],
+ "noImplicitAny": true,
+ "noImplicitThis": true,
+ "strictFunctionTypes": true,
+ "strictNullChecks": true,
+ "types": [],
+ "noEmit": true,
+ "forceConsistentCasingInFileNames": true
+ },
+ "files": [
+ "index.d.ts",
+ "lib/addressparser/index.d.ts",
+ "lib/base64/index.d.ts",
+ "lib/dkim/index.d.ts",
+ "lib/dkim/message-parser.d.ts",
+ "lib/dkim/relaxed-body.d.ts",
+ "lib/dkim/sign.d.ts",
+ "lib/fetch/cookies.d.ts",
+ "lib/fetch/index.d.ts",
+ "lib/json-transport/index.d.ts",
+ "lib/mail-composer/index.d.ts",
+ "lib/mailer/index.d.ts",
+ "lib/mailer/mail-message.d.ts",
+ "lib/mime-funcs/index.d.ts",
+ "lib/mime-funcs/mime-types.d.ts",
+ "lib/mime-node/index.d.ts",
+ "lib/mime-node/last-newline.d.ts",
+ "lib/qp/index.d.ts",
+ "lib/sendmail-transport/index.d.ts",
+ "lib/sendmail-transport/le-unix.d.ts",
+ "lib/sendmail-transport/le-windows.d.ts",
+ "lib/ses-transport/index.d.ts",
+ "lib/shared/index.d.ts",
+ "lib/smtp-connection/data-stream.d.ts",
+ "lib/smtp-connection/http-proxy-client.d.ts",
+ "lib/smtp-connection/index.d.ts",
+ "lib/smtp-pool/index.d.ts",
+ "lib/smtp-pool/pool-resource.d.ts",
+ "lib/smtp-transport/index.d.ts",
+ "lib/stream-transport/index.d.ts",
+ "lib/well-known/index.d.ts",
+ "lib/xoauth2/index.d.ts",
+ "nodemailer-tests.ts"
+ ]
+}