SENDING · Published 2026-10-06 · Updated 2026-10-06 · SecureSMTP
Receiving email
Point a domain’s MX at us and get every incoming email posted to your server.
Point a domain’s MX record at SecureSMTP and every email sent to that domain is posted to your server as the raw message. A common use: set an address on that domain as the Reply-To of the mail you send, so replies reach your app instead of a shared mailbox.
Set up
- In the dashboard, open Sites, then the site’s Inbound email page (
/app/forms/sites/<site id>/inbound). - Add a domain and the HTTPS URL that should receive messages. Use a subdomain you do not receive normal mail on, for example
reply.example.com. - Save the secret shown after you add the domain. It starts with
qcs_in_and is shown only once. If you lose it, use Rotate secret. - Add the MX record below at your DNS host, then click Check MX.
- Click Send test message to post a sample email to your URL through the same path real mail takes.
| Type | Name | Value | Priority |
|---|---|---|---|
| MX | reply.example.com | mx1.securessmtp.com | 10 |
- Mail to any address at the domain is accepted and posted to your URL.
- A site can have up to 5 inbound domains. A domain can belong to only one site.
- The URL must start with
https://. Redirects are not followed: a 3xx answer counts as a failure. - Do not use a domain whose mail you read in a normal mailbox: changing its MX sends all of its mail to your URL instead.
What we post
The request body is the full email in RFC 822 format (headers and MIME body, as received), not JSON. These headers come with it:
| Header | Value |
|---|---|
Content-Type | message/rfc822 |
User-Agent | SecureSMTP-Inbound/1.0 |
X-QCS-Event | email.inbound |
X-QCS-Signature | sha256= followed by the hex HMAC-SHA256 of the raw body, keyed with your secret |
X-QCS-Delivery | A UUID for this delivery. |
X-QCS-Domain | Your inbound domain. |
X-QCS-Recipient | The envelope recipient: the address the mail was sent to. |
X-QCS-Sender | The envelope sender (return path). Can be empty for bounce messages. |
X-QCS-Timestamp | Unix time in seconds when we posted. Not covered by the signature. |
Messages can be up to 25 MB.
Verify and read the message
The signature works like the one on event webhooks: HMAC-SHA256 of the raw body, keyed with the whole secret including qcs_in_, compared in constant time.
// npm install express mailparser
import crypto from 'node:crypto';
import express from 'express';
import { simpleParser } from 'mailparser';
const app = express();
const SECRET = process.env.SECURESSMTP_INBOUND_SECRET; // qcs_in_...
app.post(
'/inbound/securessmtp',
express.raw({ type: 'message/rfc822', limit: '30mb' }),
async (req, res) => {
const expected = 'sha256=' + crypto.createHmac('sha256', SECRET).update(req.body).digest('hex');
const received = req.get('X-QCS-Signature') || '';
const valid =
received.length === expected.length &&
crypto.timingSafeEqual(Buffer.from(received), Buffer.from(expected));
if (!valid) return res.status(401).end();
const mail = await simpleParser(req.body);
console.log({
recipient: req.get('X-QCS-Recipient'),
sender: req.get('X-QCS-Sender'),
messageId: mail.messageId,
subject: mail.subject,
text: mail.text,
attachments: mail.attachments.map((a) => a.filename),
});
// Store it, then answer 2xx.
res.status(200).end();
},
);
app.listen(3000);Responses and retries
- Answer with a 2xx status once you have stored the message. Our mail server then accepts the email from the sender.
- Anything else, or no answer within 12 seconds, is a failure. We try once more after 1.5 seconds. If that fails too, our mail server gives the sender a temporary error (
450), and the sender’s mail server tries again later on its own schedule. Mail is not lost while your endpoint is down, as long as the sender keeps retrying. - Each new attempt from the sender has a new
X-QCS-Delivery. To avoid storing a message twice, use the email’s ownMessage-IDheader as the key. - If the domain was removed or switched off, mail to it is refused with
550.
Recent messages
The Inbound email page lists the last 25 messages received for the site’s inbound domains: when, from, to, subject, size, and what your endpoint answered (delivered or failed, with the HTTP status or error). Each domain also shows whether its MX is verified and its delivered and failed counts.