Skip to content
Claim your free business email

SMTP relay: what it is, when you need one, and how to set one up

Published Updated 18 min readBy the Rasket team

Written for developers, startup founders and e-commerce teams

SMTP relay: one envelope handed between two relay towers along a single beam of light.

An SMTP relay is a mail server that accepts mail from your software over an authenticated, encrypted connection and delivers it to each recipient’s mail server, retrying when one is busy. You need one when the software that sends only speaks SMTP: WordPress and WooCommerce, an auth service such as Supabase, a framework mailer, an office scanner.

A common first encounter: a WooCommerce store goes live and customers write in asking where their order confirmation is. WordPress handed the mail to PHP’s mail() on the web server, nothing signed it for your domain, and receiving servers rejected it or filed it as spam. A relay fixes the sending half. Store owners can go straight to WordPress and WooCommerce; developers to the framework settings.

SMTP or an API? If you cannot change the code that sends, use SMTP. If you write that code, an HTTP API is usually the better fit: each request gets a status and a JSON error, and there is no connection to keep healthy. Email API vs SMTP has the full comparison. Either way, relayed mail is billed like API mail: Free covers 3,000 emails a month, and 50,000 a month is $20 on the cheapest paid plan (pricing).

What is an SMTP relay?

RFC 5321, the SMTP standard, defines a relay as a server that “receives mail from an SMTP client and transmits it” to another server “for further relaying or for delivery”. An SMTP relay service runs that server for you: you get a host name, a port and a login, and it handles delivery, retries and the signatures receivers check.

The login is not optional. A server that passes on mail from anyone is an open relay, spammers find and use it, and its address ends up on blocklists (the blocklist guide covers getting off one). A relay only sends: reading mail at your business address is email hosting, a different product (the business email post).

When do you need an SMTP relay?

The usual cases are below. A hosted store such as Shopify sends its order emails from its own servers, so there is no SMTP setting to change; authenticate your domain under Settings → Notifications → Sender email in Shopify instead.

Software that needs an SMTP relay
SoftwareWithout a relayWhat to change
WordPresswp_mail() hands mail to PHPMailer, which uses PHP's mail() and sends from wordpress@ your site's domainAn SMTP plugin, or a phpmailer_init hook, and the From address
WooCommerceSends every store email (new order, processing, completed, refunded, customer note) through wp_mail(), with a From address of its ownThe WordPress change, then WooCommerce's own From address
Supabase AuthSupabase's built-in mailer delivers only to your project team's addresses, 2 messages an hour (Supabase docs, October 2026)Custom SMTP settings. Supabase then applies its own cap of 30 auth emails an hour, which you raise under Authentication → Rate Limits
Laravel, Rails, Django, Nodemailer, printersAlready speak SMTPSettings only, if the device does TLS 1.2 and a login
Help desksAlready speak SMTPSettings, but check reply threading: the relay replaces the Message-ID (see the last section)

Which port and settings should a relay use?

Use 465 if your client offers it: the connection is encrypted with TLS from the first byte, called implicit TLS. Otherwise use 587, which starts in plain text and upgrades with STARTTLS before the login. Port 25 is for servers delivering to each other, and Rasket does not offer it. The SMTP guide explains where the three ports came from, and Email API vs SMTP which hosts block them.

Host:      smtp.rasket.com
Port:      465 (implicit TLS) or 587 (STARTTLS)
Alternate: 2465 (implicit TLS) or 2587 (STARTTLS)
Username:  rasket
Password:  an API key (rk_…) with sending access

The alternates behave the same, for networks that block the usual port. A firewall needs outbound TCP to smtp.rasket.com on the port you use; there is no fixed IP range to allow, so allow it by name.

The encryption setting per client
ClientPort 465Port 587
WordPress (PHPMailer's SMTPSecure)ssltls
Nodemailersecure: truesecure: false, requireTLS: true
Django 6.1+, MAILERS OPTIONS (EMAIL_USE_* before)"use_ssl": True"use_tls": True (never both)
Rails Action Mailertls: trueenable_starttls: true
Laravel, newer config/mail.phpMAIL_SCHEME=smtpsMAIL_SCHEME=smtp
Python smtplibsmtplib.SMTP_SSLsmtplib.SMTP, then starttls()

“SSL” in a plugin dropdown is the old name for implicit TLS, and “TLS” there means STARTTLS: PHPMailer, which wp_mail() sends through, defines 'ssl' as SMTPS and 'tls' as STARTTLS. Crossing them is the usual first failure: “TLS” on 465 hangs until it times out, and “SSL” on 587 fails at once with a TLS error.

Which DNS records does the relay need?

DNS records are public notes about your domain, added wherever its DNS is hosted, usually the company you bought the domain from. The domain page lists every record to copy; the domain verification post walks through pasting them at a registrar, including the one-click route for registrars that support it.

DNS records a Rasket domain can show
RecordWhereNeeded for the relay?
DKIM: one TXT holding a public key, 2048-bit by default; it signs every message for your domainrasket._domainkey.<your domain>Yes
Sending: one CNAME, or an MX plus an SPF TXT; the page shows one formThe return path, a subdomain such as rasket.<your domain>Yes
Receiving: one MXYour domain, or a subdomainNo. Only to receive mail at Rasket; never publish it where staff mailboxes already receive
Tracking: one CNAMElinks.<your domain>No. Open and click tracking

You do not edit your existing SPF record, the list of servers allowed to send as your domain: the relay sets the envelope sender to the return-path subdomain whatever your mailer puts in MAIL FROM, and its SPF lives there. You add no include: at the root and spend none of SPF’s 10 DNS lookups. Under DMARC’s default relaxed alignment, SPF and DKIM both align with your From domain; with strict SPF alignment (aspf=s) only DKIM does, which is still enough for DMARC to pass. In short: leave your SPF record alone, and DMARC passes either way.

DMARC itself is yours to publish. When your domain has none, its page offers a starter p=none record that only collects reports, and the DMARC guide covers moving to p=reject. Records usually resolve within an hour, or within their TTL. Once a test message arrives, read its verdicts: SPF, DKIM and DMARC should each pass, with your domain as the DKIM signer.

How to set up an SMTP relay, step by step

  1. Verify a sending domain — Add the domain the mail will come from, publish the DKIM and sending records its page lists, and wait until it reads verified.
  2. Create a key for the relay — Create an API key with sending access, restricted to that domain. It is the SMTP password; keep it in an environment variable.
  3. Enter the settings and the From address — Put the host, port, username and key into the client, with the encryption setting that matches the port, and a From address on the verified domain.
  4. Send a test and read the reply — Send one message to an address you can read. 250 2.0.0 carries the email's id; 4xx means retry later; 5xx means something has to change.

Settings → SMTP in the dashboard creates the key, fills the settings in and sends a test; from a terminal, this standard-library script does the same. Its X-Rasket-Tags header takes name=value pairs separated by commas. After the 250, a webhook or the Emails page tells you what happened, because the relay never mails a bounce back.

import os, smtplib, ssl
from email import policy
from email.message import EmailMessage
from email.utils import make_msgid

host = os.environ.get("RASKET_SMTP_HOST", "smtp.rasket.com")
port = 465  # implicit TLS; 2465 if your network blocks 465

msg = EmailMessage(policy=policy.SMTP)  # CRLF line endings, as SMTP requires
msg["From"] = os.environ["MAIL_FROM"]  # on a domain you verified
msg["To"] = os.environ["MAIL_TO"]
msg["Message-ID"] = make_msgid(domain=msg["From"].split("@")[-1])
msg["Subject"] = "Relay test"
msg["X-Rasket-Tags"] = "category=relay-test"
msg.set_content("If you can read this, the relay settings work.")

with smtplib.SMTP_SSL(host, port, context=ssl.create_default_context()) as smtp:
    smtp.login("rasket", os.environ["RASKET_API_KEY"])
    code, reply = smtp.mail(msg["From"])
    if code != 250:
        raise SystemExit(f"MAIL FROM refused: {code} {reply.decode()}")
    code, reply = smtp.rcpt(msg["To"])
    if code != 250:
        raise SystemExit(f"RCPT TO refused: {code} {reply.decode()}")
    code, reply = smtp.data(msg.as_bytes())
    print(code, reply.decode())  # 250 2.0.0 Queued as <email id>, or the refusal
250 2.0.0 Queued as 01a148de-30f2-7894-9e5e-5acbbcb214ef

Cutting over from another relay

  • Verify the domain while the old provider still sends; its records stay published.
  • Move one sender at a time and read its first replies in the mailer’s log.
  • To roll back, put the old host and credentials back. DNS stays as it is.
  • About a week after the last switch, once the old queues have drained, remove the old provider’s records, including any include: it added to your root SPF.

Set it up in WordPress and WooCommerce

For a store owner, the whole job is five steps:

  • Verify your domain (the DNS section above).
  • Create an API key with sending access, restricted to the store’s domain, so a leaked one can only send as the store.
  • Install an SMTP plugin that keeps an email log and can resend a failed message (the free FluentSMTP is one), and enter host smtp.rasket.com, port 465, encryption SSL, authentication on, username rasket, the key as the password, and a From email on your verified domain.
  • Set WooCommerce’s own sender address, as below.
  • Place a test order and check the order email arrives and shows on the Emails page.

Rasket's own WordPress plugin, which sends over the API instead, is not in the plugin directory yet. Without a plugin, this hook in a small plugin file or your theme’s functions.php does the same as step 3:

add_action('phpmailer_init', function ($mailer) {
    $mailer->isSMTP();
    $mailer->Host = 'smtp.rasket.com';
    $mailer->Port = 465;
    $mailer->SMTPSecure = 'ssl';
    $mailer->SMTPAuth = true;
    $mailer->Username = 'rasket';
    $mailer->Password = getenv('RASKET_API_KEY');
});

add_filter('wp_mail_from', fn () => 'shop@acme.example');
add_filter('wp_mail_from_name', fn () => 'Acme');

On shared hosting, or a PHP-FPM host that clears the environment, put define('RASKET_API_KEY', 'rk_…'); in wp-config.php and use $mailer->Password = RASKET_API_KEY; instead.

Every WooCommerce email goes through wp_mail(), so every one of them uses the relay: new order, processing, completed, refunded, customer note and account emails. None is sent another way unless a plugin replaces WooCommerce’s mailer. WooCommerce does set its own From address on its emails, and for those it wins over the filters above. Its default is the site’s admin email; if that is not on your verified domain, WordPress’s own login emails go out while every WooCommerce email is refused with 550 5.7.1. Change it under WooCommerce → Settings → Emails, in the sender options.

How to tell an order email failed

  • The plugin’s email log is the first place to look: it records each attempt with the relay’s reply. A 250 is accepted; anything starting 4 or 5 failed. wp_mail() tries once, so a temporary 4xx is lost unless you resend it from the log.
  • The Logs page in the dashboard, filtered to SMTP, shows every message that reached the API, refusals included, with the HTTP status and error message. Refusals at the relay itself (a wrong key, a message over 4 MB) appear only in the plugin’s log.
  • The Emails page shows each accepted email and what happened next: delivered, bounced, or suppressed. A suppressed customer, one who bounced or complained before, is accepted with a 250 and skipped. If that was a mistake (a typo the customer has since fixed), remove the address under Emails → Suppressions, then resend.

Newsletters: send them as campaigns, not through the relay

The relay is for order and account emails. A newsletter plugin that sends through wp_mail() loses its List-Unsubscribe header on the way, and with it the one-click unsubscribe Gmail and Yahoo require on bulk senders’ marketing mail. When the same content without an unsubscribe link reaches 500 people within 24 hours, your admins get a warning, and later sends like it are refused with 550 5.7.1 (the newsletter rules). Order confirmations are not caught by this: an order number or a total makes each copy different. Abandoned-cart, review-request and back-in-stock emails are marketing too. Send all of these as campaigns, which add the unsubscribe link for you, or as automations with the {{{UNSUBSCRIBE_URL}}} variable in the template (the newsletter API post).

For developers: login, Laravel, Supabase and Nodemailer

How the relay checks the login

The username is rasket for everyone; the password is an API key with sending access. Each relayed message appears on the Logs page with the key that sent it, so one key per sender tells you which one misbehaved. PLAIN and LOGIN carry the key unencrypted, so the relay offers AUTH only inside TLS; on 587 it leaves AUTH out of its feature list until STARTTLS has run, as RFC 4954 asks.

import os, smtplib, ssl

host = os.environ.get("RASKET_SMTP_HOST", "smtp.rasket.com")
port = int(os.environ.get("RASKET_SMTP_PORT", "587"))

with smtplib.SMTP(host, port) as smtp:
    smtp.ehlo()
    print("before TLS, AUTH offered:", smtp.has_extn("auth"))
    print("AUTH anyway:", smtp.docmd("AUTH", "PLAIN"))
    smtp.starttls(context=ssl.create_default_context())
    smtp.ehlo()
    print("after TLS, AUTH offered:", smtp.esmtp_features.get("auth"))
before TLS, AUTH offered: False
AUTH anyway: (538, b'5.7.11 Must issue a STARTTLS command first')
after TLS, AUTH offered:  PLAIN LOGIN

The relay answers AUTH-before-TLS with 538 5.7.11; many servers use 530 5.7.0 (RFC 3207) instead. Treat both the same: turn on STARTTLS or move to 465. Three failed logins close the connection, and ten from one IP address within 15 minutes lock that address out for 15 minutes (421 4.7.0 at connect), so one printer retrying a wrong key can lock out every device behind the office IP. The relay requires TLS 1.2 or later, which RFC 8314 requires submission servers to support.

Laravel

MAIL_MAILER=smtp
MAIL_SCHEME=smtps
MAIL_HOST=smtp.rasket.com
MAIL_PORT=465
MAIL_USERNAME=rasket
MAIL_PASSWORD="${RASKET_API_KEY}"
MAIL_FROM_ADDRESS="hello@acme.example"
MAIL_FROM_NAME="Acme"

Your config/mail.php decides the variable, not the Laravel version: the skeleton file has read MAIL_SCHEME since commit eb8085c of 13 December 2024, and older files read MAIL_ENCRYPTION. On 465 both connect with implicit TLS, because Symfony Mailer underneath turns it on for that port. MAIL_SCHEME=tls fails: Symfony Mailer 7.2 and later accepts only smtp and smtps. Define RASKET_API_KEY above MAIL_PASSWORD in .env, or in the server’s environment: .env expands ${...} only from values it already has.

Supabase Auth

Under Authentication, open the SMTP settings, turn on custom SMTP and enter the values above. Supabase then applies the hourly cap in the table above, its own and not the relay’s: raise it under Authentication → Rate Limits before a launch. The supabase/config.toml form, and Rails and Django, are in the SMTP docs’ setup guides.

Nodemailer, pooled

The relay advertises PIPELINING, so Nodemailer sends its RCPT TO commands in one batch without being asked. For more than a handful of messages, pool the connections and cap the rate:

import nodemailer from "nodemailer";

// Port 587 with STARTTLS. One pool per process: up to 5 connections, a fresh
// one after 100 messages (the relay's per-connection limit), at most 10 messages a second.
const transporter = nodemailer.createTransport({
  host: process.env.RASKET_SMTP_HOST ?? "smtp.rasket.com",
  port: Number(process.env.RASKET_SMTP_PORT ?? 587),
  secure: false,
  requireTLS: true,
  pool: true,
  maxConnections: 5,
  maxMessages: 100,
  rateLimit: 10, // per second (rateDelta defaults to 1000 ms)
  auth: { user: "rasket", pass: process.env.RASKET_API_KEY },
});

// Resolves with the email id from "250 2.0.0 Queued as <id>". Retries a 451 whose reply
// names a short wait (the rate limit); a quota or spend-cap 451 is thrown, not retried.
async function send(mail, attempt = 1) {
  try {
    const info = await transporter.sendMail(mail);
    if (info.rejected.length > 0) console.warn("not sent to", info.rejected); // 452 4.5.3
    return info.response.split(" ").pop();
  } catch (error) {
    const wait = Number(/retry after (\d+) s/.exec(error.response ?? "")?.[1]);
    if (error.responseCode !== 451 || !(wait <= 60) || attempt === 3) throw error;
    await new Promise((resolve) => setTimeout(resolve, wait * 1000));
    return send(mail, attempt + 1);
  }
}

const results = await Promise.allSettled(
  Array.from({ length: 150 }, (_, i) =>
    send({
      from: process.env.MAIL_FROM,
      to: process.env.MAIL_TO,
      subject: `Pool test ${String(i + 1)}`,
      text: "Sent through a pooled connection.",
    }),
  ),
);
const failed = results.filter((result) => result.status === "rejected");
console.log(`${String(results.length - failed.length)} accepted, ${String(failed.length)} failed`);
transporter.close();
150 accepted, 0 failed

maxMessages: 100 matches the relay’s per-connection limit, so Nodemailer reconnects before the relay asks it to. The rate limit is per team and the same on every plan, shared by every key, the API and the relay, so rateLimit: 10 is right for one process that sends nothing else; split it across workers. The 10 connections allowed from one IP address count every worker behind it.

Nodemailer retries nothing itself, so send() does: a rate-limit 451 names its wait (retry after 1 s), while a quota or spend-cap one would not clear in time. The id it returns, from info.response, is what webhook events carry, so store it: the Message-ID will not survive. A wrong key fails with 535 5.7.8 Authentication credentials invalid, and requireTLS stops the send if the STARTTLS upgrade does not happen.

A message to more than 50 recipients is a partial send: the relay refuses each extra address with 452 4.5.3, Nodemailer sends to the ones accepted and lists the rest in info.rejected. Check it, or split the list first: RFC 5321 expects servers to take at least 100 recipients, so a mailer built on that number sends more than the relay takes.

What do the relay's limits and reply codes mean?

Each relayed message is one POST /emails made with your key, so it counts against the same 10-a-second team rate as the API (the rate limits post explains the bucket). A reply’s first digit decides what your mailer does: 2 success, 4 retry later, 5 change something. The x.y.z after it is an enhanced status code (RFC 3463), and the text is the API’s own error message.

SMTP relay limits
LimitValueOver it
Message size4,000,000 bytes raw, attachments included (files of a little under 3 MB after base64). Fixed552 5.3.4
Recipients per message50 across To, Cc and Bcc; 10 until the account has a verified domain and a payment method452 4.5.3 per extra recipient
Request rate, daily and monthly quota, spend capShared with the API451 4.7.1
Messages per connection100, then reconnect421 4.7.0
Connections from one IP address10 at a time421 4.7.0
Idle connection5 minutes between commands421 4.4.2
Common SMTP relay replies
ReplyMeaningWhat to do
250 2.0.0 Queued as <id>Accepted; the text carries the email's idNothing
421 4.7.0Too many connections, or a login lockoutReconnect later
451 4.7.1The rate limit, a quota or the spend cap; the text names whichSee below
535 5.7.8Wrong username, or a bad, revoked or suspended keyFix the credentials
538 5.7.11AUTH before TLSUse 465, or turn on STARTTLS
550 5.7.1From domain not verified, the key may not send from it, or a newsletter without an unsubscribe linkVerify the domain, or see the newsletter rule above
550 5.6.0Message refused, for example the Bcc-only rule belowChange the message
552 5.3.4Over 4 MBSend large files as a link

A 451 4.7.1 for the rate limit clears in a second. One for a monthly quota or the spend cap will not clear by waiting: it can outlast a mail queue’s give-up time, which RFC 5321 puts at “at least 4-5 days”, and then the mailer bounces the message to its own sender. The relay uses X.7.1 for every limit, so only the text tells them apart; act on the email and banner team admins get at 80 % and 100 % of the monthly allowance. The SMTP docs list the rarer replies.

What happens after the relay answers 250?

250 means accepted, not delivered. The id in the reply is the email’s id, the same one an API send returns. Looking it up needs a full-access key; the relay’s sending-only key gets 401 restricted_api_key here:

curl -s "${RASKET_API_URL:-https://api.rasket.com}/emails/$EMAIL_ID" \
  -H "Authorization: Bearer $RASKET_FULL_ACCESS_KEY"
{
  "id": "01a148de-30f2-7894-9e5e-5acbbcb214ef",
  "last_event": "queued",
  "tags": { "category": "relay-test" }
}

On a read, tags come back as an object keyed by name, here from the X-Rasket-Tags header the test set. Later webhook events (email.delivered, email.bounced, email.complained and the rest) carry the same id and the same tags; the webhooks post shows how to receive them. A suppressed recipient is accepted and skipped, with an email.suppressed event; the suppression list post says which suppressions apply.

Sending the same message twice

A mailer that loses the connection after sending the message, before it reads the reply, sends it again. The relay catches that: it derives an idempotency key from the message’s own Message-ID, as your client wrote it, plus the envelope sender and recipients, and for 24 hours the same message under that key returns the first email’s id instead of sending a second.

  • No Message-ID, no key: nothing is de-duplicated. Python’s EmailMessage adds none, which is why the test script sets one.
  • A message that reuses a Message-ID but differs in content (subject, body, recipients, attachments; anything but its Date, Message-ID and MIME boundaries) is sent as a new email, because some clients reuse one by mistake.
  • An app that rebuilds a message to retry it usually writes a new Message-ID, so set X-Rasket-Idempotency-Key (1–256 characters) yourself. That header wins over the derived key; reusing it on a different message is refused with 554 5.6.0, and a duplicate that arrives while the first is still in progress gets 451 4.4.0.

What the relay changes, and what it refuses

RFC 5321’s relay passes a message on unchanged. Rasket’s is strictly a submission server (RFC 6409), and it changes messages further than that RFC’s own examples:

  • Message-ID is replaced with one Rasket assigns, after the idempotency key above is read. In-Reply-To and References are kept, so mail apps thread replies, but a help desk that matches replies against the Message-ID it generated will not find them. Thread on a ticket number in the subject or a per-ticket Reply-To address, if it offers either.
  • Internal headers are dropped. Received lines your servers added are not forwarded; your own X- headers are.
  • List-Unsubscribe is dropped, and a marketing unsubscribe does not stop relay mail.
  • Bcc-only mail is refused with 550 5.6.0: at least one address in the To: header must also be an envelope recipient (RCPT TO).
  • S/MIME and PGP are refused, because rebuilding the message would break the signature.
  • Old devices without TLS 1.2 or a login cannot connect. A small local relay such as Postfix, accepting only that device’s address, can take their mail and log in upstream; never let it accept mail from anyone else.

Whichever path you take, start with the domain and one key restricted to it, send a test from Settings → SMTP, and only then change the software that sends.

Frequently asked questions

What happens to relayed mail when we reach the month's email allowance?

On a paid plan with a payment method, pay-as-you-go is on by default: mail keeps going and the extra emails are billed at the end of the month, up to the project's spend cap. On Free, or with pay-as-you-go off, the allowance is a hard stop and the relay answers 451 4.7.1 until you upgrade or turn it on. Team admins get an email and a banner at 80% and 100%, and a campaign running out of its allowance never stops relayed mail.

Will moving to an SMTP relay service get my store's emails out of the spam folder?

It fixes the authentication part: mail is signed with DKIM for your domain and its SPF aligns, which mail sent by a web server's own mail() usually lacks. Placement also depends on your domain's reputation, complaint rate and content, so publish DMARC too and see the guide to emails going to spam if messages still land there.

Do I need an SMTP relay if my store runs on Shopify?

No. Shopify sends order and shipping notifications from its own mail servers, and there is no SMTP setting for them. What helps there is authenticating your domain under Settings, Notifications, Sender email, so the notifications are signed for your domain instead of being sent from a Shopify address.

Can one relay key send mail for several domains?

Yes, if the key is not restricted: a key with sending access can send from any domain your team has verified. A key restricted to one domain can send only from it, and anything else is refused with 550 5.7.1. Restricted keys are the safer choice for devices and plugins.

Will sending through an SMTP relay get my order emails out of Gmail's Promotions tab?

Not by itself. Gmail picks the tab from the message and from how recipients treat your mail, not from the server that relayed it. Keep order emails free of promotional blocks and offers, and see the Gmail Promotions tab guide for what moves mail between tabs.

Does the SMTP relay server keep a copy of what my application sent?

Every relayed message is stored as an email you can open on the Emails page or fetch with GET /emails/{id}, like an API send, and each one appears on the Logs page with the API key that sent it.

Sources

  1. RFC 5321: Simple Mail Transfer Protocol (§2.3.10 relay, §4.5.4.1 retry) — IETF, read 2026-10-17
  2. RFC 6409: Message Submission for Mail — IETF, read 2026-10-17
  3. RFC 4954: SMTP Service Extension for Authentication (§6 status codes) — IETF, read 2026-10-17
  4. RFC 3207: SMTP Service Extension for Secure SMTP over Transport Layer Security — IETF, read 2026-10-17
  5. RFC 8314: Cleartext Considered Obsolete: Use of Transport Layer Security (TLS) for Email Submission and Access — IETF, read 2026-10-17
  6. RFC 9989: Domain-Based Message Authentication, Reporting, and Conformance (DMARC) — IETF, read 2026-10-17
  7. RFC 3463: Enhanced Mail System Status Codes — IETF, read 2026-10-17
  8. Send emails with custom SMTP — Supabase, read 2026-10-17
  9. Rate limits (emails sent by Supabase Auth, customizable with custom SMTP) — Supabase, read 2026-10-17
  10. WC_Email::send(): every WooCommerce email goes through wp_mail() by default — WooCommerce, read 2026-10-17
  11. Migrating email to mailers (EMAIL_USE_SSL and EMAIL_USE_TLS become use_ssl and use_tls) — Django, read 2026-10-17
  12. SMTP relay settings, limits and replies — Rasket, read 2026-10-17
  13. Rasket pricing: plans, included emails and pay-as-you-go — Rasket, read 2026-10-17
  14. Setting up your email: authenticating your sender domain — Shopify, read 2026-10-17
  15. FluentSMTP: email logs and resending failed emails — WordPress.org, read 2026-10-17
  16. laravel/laravel: config/mail.php history (MAIL_SCHEME since 13 December 2024) — Laravel, read 2026-10-17
  17. config/mail.php in the Laravel 10.x application skeleton (MAIL_ENCRYPTION) — Laravel, read 2026-10-17
  18. EsmtpTransportFactory: supported schemes smtp and smtps (Symfony Mailer 7.2) — Symfony, read 2026-10-17
  19. PHPMailer: ENCRYPTION_STARTTLS ('tls') and ENCRYPTION_SMTPS ('ssl') — PHPMailer, read 2026-10-17
  20. wp_mail() in wp-includes/pluggable.php — WordPress, read 2026-10-17
  21. SMTP transport — Nodemailer, read 2026-10-17
  22. Pooled SMTP connections (maxConnections 5, maxMessages 100, rateDelta, rateLimit) — Nodemailer, read 2026-10-17
  • SMTP — Send from anything that speaks SMTP: settings, setup guides, limits and replies.
  • What is SMTP? How email actually gets delivered — What SMTP is and how email gets delivered: the four hops, ports 25, 465 and 587, reply codes like 550, and MTA-STS vs DANE for mail servers.
  • Email API vs SMTP: which should you use? — Use an email API when you can change the sending code, and SMTP when you can't. A decision table, one email sent both ways, and which ports get blocked.
  • Email API rate limits: headers and backoff — Email API rate limits, measured: the ratelimit headers Rasket sends, what a 429 looks like, and Node and Python backoff that retries without sending twice.
  • Email webhooks explained: events and signatures — Email webhooks explained: the delivery events, the payload, HMAC signature verification, retries, and complete tested receivers in Node and Python.
  • Domains — The records, where they go at each registrar, and what the page does while you wait.
  • STARTTLS — STARTTLS is the SMTP command that upgrades a plain connection to an encrypted one. The receiving server advertises support, the sender asks to upgrade, and…
  • MTA (mail transfer agent) — An MTA is a program that moves email between servers. It accepts a message, decides where it should go next by looking up the recipient domain's MX record,…
  • How to get out of the Gmail Promotions tab — Why Gmail files your email under Promotions, what it costs you, and the steps that move mail toward Primary, with an example welcome-email line to copy.

Start sending this morning

Sign up, verify a domain and send your first email in minutes.