DEV Community

Cover image for Founders, SaaS Builders, Developers: Make Your Transactional Emails Actually Work
Francisco Inoque
Francisco Inoque

Posted on

Founders, SaaS Builders, Developers: Make Your Transactional Emails Actually Work

Transactional Emails: What They Are and How to Send Them with Node.js

Sooner or later, every software product needs to send emails.

Are you a founder, a SaaS builder, or a software maintainer?

No matter what you build, if you work with software long enough, there will come a day when you need to send transactional emails.

Password resets, email verification, login alerts, invoices, OTP codes. These emails are everywhere. Users rarely notice them when they work, but when they fail, your product immediately feels broken.

So what exactly are transactional emails, and how should developers handle them?


What Are Transactional Emails?

Transactional emails are automatic, one-to-one messages triggered by a user action or a system event.

They are not marketing emails.

They are part of your product’s core functionality.

Common examples include:

  • Account verification emails
  • Password reset emails
  • Login or security alerts
  • Payment confirmations and invoices
  • OTP and two-factor authentication emails

These emails must be delivered fast, reliably, and to the inbox. If a password reset email lands in spam or arrives too late, users lose trust instantly.

That is why transactional emails are not just “emails”.

They are part of your authentication flow, security layer, and user experience.


Why Developers Should Care About Deliverability

Transactional emails usually have low volume but high importance.

You are not sending newsletters.

You are sending critical system messages.

This means:

  • Timing matters
  • Inbox placement matters
  • Reputation matters

Many teams separate transactional and marketing emails entirely. Different domains, different infrastructure, and stricter sending rules help protect deliverability.

Ignoring this early often leads to painful problems later.


Installing the Metigan SDK

To send transactional emails with Metigan, start by installing the SDK.

Using npm:

npm install metigan or yarn add metigan
Enter fullscreen mode Exit fullscreen mode

Initializing Metigan

After installation, initialize Metigan with your API key.

import Metigan from 'metigan';

const metigan = new Metigan({
  apiKey: "sp_63ace7496fb7692b6cace7496fb7692b6cace8f77d3d1bf8bc0db95cd944d498cbfc7679a1d5987b"
});
Enter fullscreen mode Exit fullscreen mode

This instance will be used to send emails and manage contacts.

Sending a Basic Email

Here is a simple example of sending an email to one or more recipients.

export const sendMail = async (recipients: string[]) => {
  try {
    const result = await metigan.email.sendEmail({
      from: "Oi <oi@metigan.com>",
      recipients,
      subject: "Message for API key test",
      content: "Hello buddy, this message is from the Metigan Node.js SDK"
    });

    return result;
  } catch (error) {
    throw new Error(error as string);
  }
};
Enter fullscreen mode Exit fullscreen mode

This type of email can be used for system notifications or internal messages.

Creating Contacts Programmatically

Many products need to store users or customers for lifecycle communication.

export const createContacts = async (email: string, audienceId: string) => {
  try {
    const contact = await metigan.contacts.create({
      email: email,
      firstName: 'John',
      lastName: 'Doe',
      phone: '+1234567890',
      tags: ['customer', 'premium'],
      customFields: {
        company: 'Acme Corp',
        jobTitle: 'Software Engineer'
      },
      audienceId: audienceId
    });

    console.log('Contact created:', contact._id);
    return contact;
  } catch (error) {
    console.error('Error creating contact:', error);
    return error;
  }
};
Enter fullscreen mode Exit fullscreen mode

This is useful for onboarding flows and future communication.

Sending Transactional Emails

Now the most important part.

export const sendTransactionalEmail = async () => {
  try {
    const result = await metigan.email.sendTransactional({
      from: 'Francisco Inoque APP <hello@franciscoinoque.com>',
      to: 'jaimeinoque20@gmail.com',
      subject: 'Welcome to Metigan!',
      content: '<p>This is your password reset link: <a href="link_to_reset">Reset Password</a></p>'
    });

    console.log('Transactional email sent successfully!');
    return result;
  } catch (error) {
    console.error('Error sending transactional email:', error);
    return error;
  }
};
Enter fullscreen mode Exit fullscreen mode


j

This pattern applies to password resets, account verification, and security notifications.

If these emails fail, users are blocked from using your product.

Sending OTP Emails

One very common transactional use case is sending One-Time Passwords (OTP).

const sendOtpEmail = async () => {
  try {
    await metigan.email.sendOtp({
      from: 'hello@example.com',
      recipients: ['user@gmail.com'],
      subject: 'Your OTP Code',
      content: '<p>Your OTP code is: <strong>123456</strong></p>',
      expiry: 300
    });

    console.log('OTP email sent successfully!');
  } catch (error) {
    console.error('Error sending OTP email:', error);
  }
};

sendOtpEmail();
Enter fullscreen mode Exit fullscreen mode

OTP emails are time-sensitive and should expire quickly. In this example, the OTP expires after 5 minutes, which is a common and safe default.

This is typically used for:

  • Login verification

  • Password reset confirmation

  • Sensitive account actions

  • Email-based two-factor authentication

Final Thoughts

Transactional emails are not optional. They are a core part of any serious software product.

As developers, treating them with the same importance as authentication, database reliability, or security pays off in the long run.

Users will never thank you when transactional emails work perfectly.
But they will complain loudly when they don’t.

If you are building a product today, start thinking about transactional emails early.

Full Documentation

For more advanced use cases and API references, check the full documentation:

👉 Metigan Developer

Top comments (0)