Email Marketing10 min read

GDPR and CAN-SPAM Compliance for Transactional Emails: What Developers Need to Know

Transactional and marketing emails have different legal rules. Learn the compliance requirements under CAN-SPAM, GDPR, and CASL — including the gray areas where most SaaS companies get fined.

R

React Emails Pro

March 6, 2026

You know you need to comply with email regulations. You've probably heard of CAN-SPAM and GDPR. But here's the part most developers get wrong: transactional emails and marketing emails have different rules. A password reset doesn't need an unsubscribe link. A trial-ending reminder might. The line between “transactional” and “marketing” is where most companies get fined.

This guide covers the compliance rules for transactional emails under CAN-SPAM, GDPR, and CASL — with specific guidance for SaaS teams shipping email from Next.js.

This post is technical guidance, not legal advice. Consult a lawyer for your specific situation, especially if you operate across jurisdictions.

$51,744

Max CAN-SPAM fine

Per non-compliant email sent

4%

Max GDPR fine

Of annual global turnover

$10M CAD

Max CASL fine

Per violation (individuals)


The legal definition of “transactional”

Under CAN-SPAM, a transactional email is one whose primary purpose is to facilitate, confirm, or complete a transaction the recipient has already agreed to. Specifically:

  • Purchase confirmations and receipts
  • Shipping notifications
  • Account security (password resets, login alerts)
  • Subscription changes (plan upgrades, cancellations)
  • Service updates that affect the user's account

What's not transactional, even if it feels like it:

  • “Your trial ends in 3 days” — this is a conversion nudge, not a transaction confirmation
  • “Check out our new feature” — product announcement, clearly marketing
  • “Users like you also bought...” — upsell content in a receipt email makes the whole email commercial
  • “We miss you” re-engagement — marketing, full stop
Key takeaway

CAN-SPAM uses a “primary purpose” test. If the email's main goal is to promote a product or service, it's commercial — even if it contains transactional information. Adding a coupon to a receipt email can reclassify the entire email.


CAN-SPAM requirements (United States)

CAN-SPAM applies to any “commercial electronic message” sent to US recipients. Transactional emails get exemptions from some requirements, but not all.

Transactional emails
  • No unsubscribe link required
  • No physical address required
  • Subject line just needs to not be deceptive
  • From address must be accurate
  • Must not contain false header info
Marketing emails
  • Unsubscribe link required (must work within 10 days)
  • Physical mailing address required
  • Subject must not be misleading about content
  • Must identify as an advertisement
  • Must honor opt-out within 10 business days
Even transactional emails must have an accurate “From” address and non-deceptive subject lines. You can't subject-line a password reset as “You just won a prize!”

GDPR requirements (EU/EEA)

GDPR doesn't distinguish between transactional and marketing emails the way CAN-SPAM does. Instead, it cares about your legal basis for processing personal data (which includes email addresses).

  • Contract performance (Art. 6(1)(b)): You can send transactional emails without explicit consent because they're necessary to fulfill a contract. Password resets, purchase confirmations, and account alerts fall here.
  • Legitimate interest (Art. 6(1)(f)): Some product emails (onboarding sequences, feature announcements for active users) may qualify, but you must document a Legitimate Interest Assessment (LIA).
  • Consent (Art. 6(1)(a)): Marketing emails, newsletters, and promotional content require explicit, freely given consent with a clear opt-in.

What GDPR requires for all emails

  1. Data minimization: Only include personal data necessary for the email's purpose.
  2. Transparency: Your privacy policy must explain what emails you send and why.
  3. Right to object: Users can object to processing based on legitimate interest. For marketing, this means easy unsubscribe.
  4. Data retention: Don't keep email logs forever. Set a retention policy (90 days for tracking data is reasonable).
  5. Processing records: Document your email processing activities (who, what, why, retention period).
Email tracking under GDPR: Open tracking pixels and click tracking constitute personal data processing. For transactional emails, you may rely on legitimate interest (with a documented LIA). For marketing emails, tracking should be covered by your consent mechanism.

CASL requirements (Canada)

Canada's Anti-Spam Legislation is the strictest of the three. Unlike CAN-SPAM (opt-out model), CASL requires express consent before sending commercial messages.

  • Transactional emails are exempt from consent requirements (same categories as CAN-SPAM)
  • All commercial emails need express or implied consent
  • Express consent means a clear opt-in (not pre-checked boxes)
  • Implied consent has a 2-year expiry from last transaction
  • Every commercial email must identify the sender, include contact info, and have an unsubscribe mechanism

The gray areas (where companies get in trouble)

Most compliance violations happen in the gray zone between transactional and marketing. Here are the common traps:

1. Upsells in transactional emails

Adding “Upgrade to Pro for 20% off” to a receipt email can reclassify the entire email as commercial under CAN-SPAM. Under GDPR, it changes your legal basis from contract performance to legitimate interest (or consent).

emails/receipt.tsx
// RISKY: This receipt email now contains commercial content
export function ReceiptEmail({ order, promoCode }: ReceiptProps) {
  return (
    <BaseLayout previewText={`Receipt for order #${order.id}`}>
      <OrderDetails order={order} />

      {/* This one section can reclassify the entire email */}
      <Section>
        <Text>Loved your purchase? Use code {promoCode} for 20% off!</Text>
      </Section>
    </BaseLayout>
  );
}

// SAFER: Keep transactional emails purely transactional
export function ReceiptEmail({ order }: ReceiptProps) {
  return (
    <BaseLayout previewText={`Receipt for order #${order.id}`}>
      <OrderDetails order={order} />
      {/* No promotional content */}
    </BaseLayout>
  );
}

2. Onboarding sequences

The first “Welcome to your account” email is transactional. The third “Have you tried feature X?” email is marketing. The line blurs around emails 2-4.

A practical rule: if the email would still make sense if the user had a free plan with no upgrade path, it's transactional. If it only makes sense as a conversion tool, it's marketing.

3. Renewal reminders

“Your subscription renews on March 15 for $49” is transactional. “Your subscription renews soon — upgrade to annual and save 20%!” is commercial. The difference is whether the primary purpose is informing or selling.


Implementation patterns for compliance

Here's how to build compliance into your email infrastructure, not bolt it on after:

Categorize emails at the template level

lib/email/types.ts
type EmailCategory = "transactional" | "marketing" | "hybrid";

type EmailTemplate = {
  name: string;
  category: EmailCategory;
  legalBasis: "contract" | "legitimate-interest" | "consent";
  requiresUnsubscribe: boolean;
  retentionDays: number;
};

// Define compliance requirements per template
const TEMPLATES: Record<string, EmailTemplate> = {
  "password-reset": {
    name: "Password Reset",
    category: "transactional",
    legalBasis: "contract",
    requiresUnsubscribe: false,
    retentionDays: 30,
  },
  "welcome": {
    name: "Welcome Email",
    category: "transactional",
    legalBasis: "contract",
    requiresUnsubscribe: false,
    retentionDays: 90,
  },
  "trial-ending": {
    name: "Trial Ending Reminder",
    category: "hybrid",
    legalBasis: "legitimate-interest",
    requiresUnsubscribe: true,      // Safer to include
    retentionDays: 90,
  },
  "feature-announcement": {
    name: "New Feature Announcement",
    category: "marketing",
    legalBasis: "consent",
    requiresUnsubscribe: true,
    retentionDays: 90,
  },
};
lib/email/send.ts
export async function sendEmail({
  to,
  userId,
  template,
  data,
}: SendEmailParams) {
  const templateConfig = TEMPLATES[template];
  if (!templateConfig) throw new Error(`Unknown template: ${template}`);

  // Transactional emails skip consent check
  if (templateConfig.legalBasis === "consent") {
    const hasConsent = await db.emailConsent.findFirst({
      where: {
        userId,
        category: "marketing",
        consentedAt: { not: null },
        revokedAt: null,
      },
    });

    if (!hasConsent) {
      console.log(`Skipping ${template} for ${userId}: no marketing consent`);
      return;
    }
  }

  // Add unsubscribe header for marketing/hybrid emails
  const headers: Record<string, string> = {};
  if (templateConfig.requiresUnsubscribe) {
    headers["List-Unsubscribe"] =
      `<${process.env.APP_URL}/api/unsubscribe?userId=${userId}>`;
    headers["List-Unsubscribe-Post"] = "List-Unsubscribe=One-Click";
  }

  await emailProvider.send({ to, subject, html, headers });
}

One-click unsubscribe

As of February 2024, Gmail and Yahoo require one-click unsubscribe via the List-Unsubscribe header for bulk senders (5,000+ emails/day). Even if you're below that threshold, implement it — it's a deliverability signal.

app/api/unsubscribe/route.ts
import { NextRequest, NextResponse } from "next/server";
import { db } from "@/lib/db";

// Handles both GET (link click) and POST (one-click header)
export async function POST(req: NextRequest) {
  const userId = req.nextUrl.searchParams.get("userId");
  if (!userId) return new NextResponse("Missing userId", { status: 400 });

  await db.emailConsent.updateMany({
    where: { userId, category: "marketing" },
    data: { revokedAt: new Date() },
  });

  // Must process within 2 days (Gmail requirement)
  return new NextResponse("Unsubscribed", { status: 200 });
}

export async function GET(req: NextRequest) {
  const userId = req.nextUrl.searchParams.get("userId");
  if (!userId) return NextResponse.redirect(new URL("/", req.url));

  await db.emailConsent.updateMany({
    where: { userId, category: "marketing" },
    data: { revokedAt: new Date() },
  });

  // Redirect to a confirmation page
  return NextResponse.redirect(
    new URL("/unsubscribed?success=true", req.url)
  );
}

The physical address requirement

CAN-SPAM and CASL require a valid physical postal address in commercial emails. If you're a remote-first company, you have options:

  • Registered agent address
  • PO Box or virtual mailbox
  • Coworking space address (if contractually allowed)

Put it in the footer of marketing emails. Transactional emails don't need it under CAN-SPAM, but including it doesn't hurt.


Compliance audit checklist

1

Classify every email template

Go through each template and classify it as transactional, marketing, or hybrid. Document the legal basis for each.

2

Add unsubscribe to marketing emails

Both a visible link in the footer and the List-Unsubscribe header. Must work within 10 business days (CAN-SPAM) or 2 days (Gmail/Yahoo).

3

Check consent flows

Verify that marketing email consent is explicit, freely given, and recorded with a timestamp. Pre-checked boxes don't count under GDPR or CASL.

4

Review email content for commercial creep

Check if transactional emails contain promotional content that could reclassify them. Remove upsells from receipts and security emails.

5

Set data retention policies

Define how long you keep email logs, tracking data, and consent records. Document this in your privacy policy.

6

Add physical address to marketing footers

A valid postal address is required in every commercial email under CAN-SPAM and CASL.


The bottom line

Email compliance isn't about checking boxes. It's about not being the company that turns a receipt email into a marketing vehicle and gets hit with a five-figure fine. Keep transactional emails purely transactional. Get real consent for marketing. And when you're in the gray zone, err on the side of caution — adding an unsubscribe link to a borderline email costs nothing.

The simplest compliance strategy: separate your sending infrastructure. Transactional emails from one subdomain, marketing from another. Different IP reputation, different consent rules, different monitoring. Read more in Transactional vs Marketing Email.
R

React Emails Pro

Team

Building production-ready email templates with React Email. Writing about transactional email best practices, deliverability, and developer tooling.

Production-ready templates

Pick from 9 template packs built with React Email. One-time purchase, lifetime updates, tested across every major email client.

Browse all templates