Here’s the full English version of this article, keeping the same structure and “real-pitfalls + step-by-step” tone.


This is a step-by-step guide that collects all the real issues I ran into when integrating Mailjet.

Goal: send transactional emails only, deliver reliably to the inbox, and avoid sending limits / suspensions.


0. Pre-Launch Checklist (Quick View)

  • Account has passed manual review / is unsuspended (Business Verification submitted and clearly states “transactional emails only”)
  • You only use your own domain for From addresses (e.g. noreply@yourdomain.com), never gmail.com / outlook.com etc.
  • SPF is a single record only, and includes include:spf.mailjet.com
  • DKIM is active (mailjet._domainkey as a TXT record, value is a single-line public key)
  • DMARC is enabled (_dmarc TXT record, even if policy is just p=none at first)
  • SMTP or Send API is working with a minimal sending example
  • Webhook is configured (you can see bounces, blocks, soft bounces, opens, clicks, etc.)
  • Real-world test with Gmail/Outlook shows: SPF=Pass / DKIM=Pass / DMARC=Pass in headers

1. Account Review & Unblocking (Business Verification)

1.1 Create the account first, then provide extra info

New accounts often see “Sending activity is suspended”.
This is usually not a config error; it means they need more business information and manual review.

1.2 What to tell support (key points)

  • We send transactional emails only (e.g. task assignment notifications, system alerts, status change notifications). No marketing, no bulk campaigns, no purchased lists.
  • Estimate of monthly sending volume (be conservative, e.g. 500–1,000 / month).
  • Recipient sources: internal staff or existing users from our own system, all are work-related notifications.
  • Attach a few sample emails (subject, recipient type, business trigger).
  • Link to your website / product.

This type of description usually speeds up the manual review.
It’s normal if the case gets passed to another team; just wait it out.


2. Only Use Your Own Domain as Sender (Avoid Free Mailboxes)

On the Sender domains & addresses page you’ll see:

  • Domains like gmail.com cannot have SPF/DKIM configured by you. Mailjet explicitly does not recommend or allow them as sending domains. This severely hurts deliverability.
  • Correct approach: add and authenticate your own domain (e.g. yourdomain.com), then use addresses such as noreply@yourdomain.com, alerts@yourdomain.com as From.

3. DNS Authentication (Cloudflare Hands-On)

Tool: Cloudflare dashboard → DNS
Goal: exactly ONE SPF record, ONE DKIM record, ONE DMARC record.

3.1 SPF (must be a single TXT record)

Pitfall #1: Duplicate SPF records → SPF is considered invalid.

You may already have SPF for Google/M365 or Cloudflare Email Routing. Adding Mailjet on top easily leads to multiple records.

Merge rule: put all necessary include: mechanisms into one single SPF record, and keep only one ~all (or -all) at the end.
Example: you need Mailjet + Cloudflare Email Routing + Google:

Name: @
Type: TXT
Value: v=spf1 include:spf.mailjet.com include:_spf.mx.cloudflare.net include:_spf.google.com ~all

Notes:

  • Order does not matter, but there must be only one SPF record.
  • Avoid duplicate include: entries, and only one ~all at the end.
  • Once active, Mailjet’s SPF check should show OK.

3.2 DKIM (TXT, pay attention to “single line”)

In Mailjet’s Domain Authentication Setup you will see:

  • Hostname: mailjet._domainkey (it becomes mailjet._domainkey.yourdomain.com)
  • Type: TXT
  • Value: a long public key starting with k=rsa; p=MIIBI...

Pitfall #2: Pasting multi-line values or adding quotes incorrectly in Cloudflare → looks correct in UI, but actually invalid.

  • Fix: remove line breaks and ensure the value is one single line.
  • Cloudflare will display quotes for you; you do not need to add extra quotes manually.

Example (do not break this line):

Name: mailjet._domainkey
Type: TXT
Value: k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A...QIDAQAB

3.3 DMARC (start with p=none)

Even if you don’t enforce anything at first, it’s worth collecting reports to see if anyone is abusing your domain:

Name: _dmarc
Type: TXT
Value: v=DMARC1; p=none; rua=mailto:dmarc@yourdomain.com; sp=none; adkim=s; aspf=s

Later you can move p=nonequarantinereject.

3.4 Other Cloudflare Gotchas

  • Root CNAME: Cloudflare supports CNAME flattening at the root for web; it does not interfere with email TXT/MX records.
  • Orange cloud proxy: TXT records for SPF/DKIM/DMARC are always DNS only, not proxied.
  • TTL: Auto or 5 minutes is fine. After editing, wait a couple of minutes and then hit Refresh in Mailjet.

4. Sending Channel: SMTP vs Send API (Either or Both)

4.1 SMTP (fastest way to start)

  • Dashboard path: Account → SMTP and SEND API settings
  • Credentials: Host: in-v3.mailjet.com, Port: 587 (STARTTLS) or 465 (SSL)
  • Auth: use Mailjet API Key as username, Secret Key as password

Example (Node.js + nodemailer):

import nodemailer from "nodemailer";

const transporter = nodemailer.createTransport({
  host: "in-v3.mailjet.com",
  port: 587,
  secure: false, // 587 with STARTTLS
  auth: {
    user: process.env.MJ_APIKEY_PUBLIC,
    pass: process.env.MJ_APIKEY_PRIVATE
  }
});

await transporter.sendMail({
  from: "noreply@yourdomain.com",
  to: "employee@yourdomain.com",
  subject: "Task Assigned #12345",
  text: "A new work package has been assigned to you.",
  html: "<p>A new work package has been assigned to you.</p>"
});

4.2 Send API (more flexible, better for structured templates)

Use HTTP POST to https://api.mailjet.com/v3.1/send with Basic Auth (API Key / Secret):

curl -X POST \
  -u "$MJ_APIKEY_PUBLIC:$MJ_APIKEY_PRIVATE" \
  -H "Content-Type: application/json" \
  https://api.mailjet.com/v3.1/send \
  -d '{
    "Messages": [
      {
        "From": {"Email": "noreply@yourdomain.com", "Name": "Your App"},
        "To":   [{"Email": "employee@yourdomain.com", "Name": "John"}],
        "Subject": "Task Completed - #67890",
        "TextPart": "A meter reading task has been completed.",
        "HTMLPart": "<strong>Reading #67890</strong> completed."
      }
    ]
  }'

Best practices

  • For transactional email, send one recipient per message; don’t stuff many employees into the same To/CC/BCC.
  • Maintain templates in Mailjet Transactional templates and treat them like versioned artifacts.
  • Use only the domain you have authenticated for all From addresses.

5. Event Webhooks & Observability

Path: Account → Event notifications (webhooks)

Common events: sent, delivered, open, click, bounce, blocked, spam, unsub (for pure transactional flows you usually won’t see unsub).

Recommendations:

  • Point to a backend endpoint like /mailjet/events, validate the source, and log the raw payload.
  • Build a small “delivery timeline” view: for each message, show send/deliver/open/click/bounce events. This makes debugging much easier.
  • For soft bounces (temporary failures), implement exponential backoff retries (e.g. 5m → 15m → 1h → 6h).

6. Verification & Troubleshooting

6.1 Quick self-test

  1. Send an email to your own Gmail/Outlook address.

  2. View original headers (Gmail → three dots → “Show original”):

    • SPF: PASS
    • DKIM: PASS (d= should be yourdomain.com or the Mailjet DKIM domain)
    • DMARC: PASS (based on the previous two)
  3. If SPF=softfail or DKIM=neutral, go back to Step 3 and double-check DNS.

6.2 Common problems list

  • Multiple SPF records → merge into a single record; keep only one ~all/-all.
  • DKIM value with line breaks / wrong quoting → store as a single line of plain text.
  • Using a free mailbox as From → switch to your own domain.
  • Sending before domain verification is done → leads to throttling or blocking.
  • Transactional email looks like marketing → keep it simple: mostly plain text + light HTML, like a system notification.
  • Aggressive retry behaviour → temporary rejections get worse if you hammer the recipient; use exponential backoff.
  • SMTP auth uses wrong credentials → make sure user/pass are API Key / Secret, not your login email password.

7. “Gray Release” Before Full Production

  • Start with a small internal group for a week: monitor delivery, open rate, bounce rate, and blocked events.
  • Throttling: even with low volumes, keep a reasonable per-minute / per-hour rate, avoid traffic spikes that might look suspicious to ISPs.
  • If the account is limited again: reuse the Section 1 template, explain transactional use, examples, recipient source, and actual sending frequency.

8. Advanced: Sub-Accounts & Environment Separation

  • Use Subaccounts or separate API Keys to isolate production vs test and different product lines. Webhooks can point to different endpoints per key.
  • Subject naming convention: [ENV] Task Assigned #12345 (clearly labeled for non-production).
  • Template variables such as {{name}}, {{task_id}}, {{date}} should be supplied by the backend. Template publishing should go through code review.

9. Minimal Working Configuration (Checklist)

Cloudflare DNS

@                  TXT  v=spf1 include:spf.mailjet.com include:_spf.mx.cloudflare.net include:_spf.google.com ~all
mailjet._domainkey TXT  k=rsa; p=MIIBIjANBgkq...QIDAQAB   // single line
_dmarc             TXT  v=DMARC1; p=none; rua=mailto:dmarc@yourdomain.com; adkim=s; aspf=s

Sender

From: noreply@yourdomain.com

Sending

  • SMTP: in-v3.mailjet.com:587 (STARTTLS)
  • Or Send API: POST /v3.1/send (Basic Auth)

Webhook

/mailjet/events  ← subscribe to sent, delivered, open, click, bounce, blocked, spam

10. FAQ

Q: SPF says “multiple SPF records, invalid”, but I need Google + Cloudflare + Mailjet. What now?
A: Combine all include: entries into one SPF record, e.g.:
v=spf1 include:spf.mailjet.com include:_spf.mx.cloudflare.net include:_spf.google.com ~all


Q: DKIM page says “DomainKey invalid”, but Cloudflare shows it saved correctly.
A: 90% of the time the value got split into multiple lines or segments. Change it to a single line value, save, then hit Refresh in Mailjet a few minutes later.


Q: Do transactional emails need an unsubscribe link?
A: True transactional notifications (strongly tied to work / system operations) do not require an unsubscribe link, but you must ensure you only send to recipients with an existing business relationship.


Q: Gmail still puts messages into Promotions or Spam?
A: For transactional messages, try:

  • Mostly plain text with light HTML
  • Minimal external links / images / tracking elements
  • Honest, non-marketing subject lines
  • From and Reply-To using the same or consistent domain
  • All three: SPF / DKIM / DMARC must PASS

Closing

If you follow these steps, you can flatten most of the tricky parts of Mailjet integration in one go:

  • Explain account usage clearly (transactional only)
  • DNS trio set up correctly (single SPF, single-line DKIM, DMARC enabled)
  • Get a minimal SMTP / Send API example working first, then add templates and webhooks
  • Run a small-scale gray release + metrics dashboard so you can quickly trace any problems

Happy sending!

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐