Why out-of-office replies don't reach your tool
Out-of-office replies are normally addressed to the SMTP envelope return path, not to the Reply-To header. RFC 3834 says an automatic responder SHOULD send its response to the Return-Path field and SHOULD NOT use Reply-To. So an outbound tool that routes replies by rewriting Reply-To to its own domain collects human replies while the conforming automatic ones go elsewhere: the away message lands in the sending mailbox, where no sequence logic is watching.
A lead is away until the 14th. Their mail server says so, politely and immediately. Your tool never hears it, sends two more follow-ups into an empty chair, and records the lead as "no reply". That is not a bug in your code. It is the protocol working exactly as specified, and the specification is RFC 3834.
Where does an out-of-office reply actually go?
To the envelope return path. Not to Reply-To, not to From. RFC 3834, "Recommendations for Automatic Responses to Electronic Mail", is a Standards Track document from August 2004, and Section 4 is unambiguous about the destination.
In general, automatic responses SHOULD be sent to the Return-Path field if generated after delivery. If the response is generated prior to delivery, the response SHOULD be sent to the reverse-path from the SMTP MAIL FROM command, or (in a non-SMTP system) to the envelope return address which serves as the destination for non-delivery reports.
RFC 3834, Section 4
Return-Path is not a header you write. It is a header the receiving server writes on your behalf, out of the envelope. RFC 5321 Section 4.4: "When the delivery SMTP server makes the 'final delivery' of a message, it inserts a return-path line at the beginning of the mail data. This use of return-path is required; mail systems MUST support it. The return-path line preserves the information in the <reverse-path> from the MAIL command."
The same RFC is blunt about what that address is for: "The reverse-path address (as copied into the Return-path) MUST be used as the target of any mail containing delivery error messages." Section 4.5.5 extends the pattern past bounces to notifications generally — non-delivery notifications, DSNs and MDNs "are notifications about a previous message, and they are sent to the reverse-path of the previous mail message." RFC 5321 does not enumerate out-of-office replies there, but RFC 3834 sends them down the same road for the same reason.
220 mx.example.net ESMTP
EHLO mail.contoso.com
250 mx.example.net
MAIL FROM:<dana@contoso.com> <-- envelope. Becomes Return-Path.
250 2.1.0 Sender OK
RCPT TO:<lead@example.net>
250 2.1.5 Recipient OK
DATA
354 Start mail input
From: Dana Okonkwo <dana@contoso.com>
Reply-To: r+7f3a91@reply.example.com <-- header. RFC 3834 says ignore it.
To: lead@example.net
Subject: Quick question about your MSP stack
...
.
250 2.0.0 OKWhy does the responder ignore Reply-To?
Because Reply-To is a human's instruction to other humans, and an automatic responder has no way to understand it. RFC 3834 Section 4 spends four paragraphs on this. Reply-To may point at an entire mailing list. From may list several addresses when a response should go to exactly one. Sender "is intended only to identify the person or entity that sent the message, and is not required to contain an address that is valid for replies".
The Return-Path address is really the only one from the message header that can be expected, as a matter of protocol, to be suitable for automatic responses that were not anticipated by the sender.
RFC 3834, Section 4
Note the phrase "not anticipated by the sender". That is the whole argument. A human reply is anticipated — you asked a question, they answer it, and honouring your Reply-To is a courtesy they choose. An out-of-office reply is not anticipated by anyone. The responder is a program with no context, so the spec routes it to the one address the protocol expects to be suitable for a response nobody asked for.
So where does the away message end up?
In whichever mailbox owns the envelope sender. For most outbound tooling built on a customer's own mailbox, that is the customer's own inbox — the one the tool deliberately does not read.
| Sending design | Envelope sender (MAIL FROM) | Reply-To header | Human reply arrives at | Auto-reply arrives at |
|---|---|---|---|---|
| Mailbox API (Graph sendMail / Gmail send), Reply-To rewritten | the mailbox address — you cannot set it | r+key@reply.example.com | your reply MX | the customer mailbox |
| Mailbox API, no Reply-To rewrite | the mailbox address | none | the customer mailbox | the customer mailbox |
| Your own SMTP with a VERP return path | bounce+key@bounce.example.com | r+key@reply.example.com | your reply MX | your bounce MX |
The first row is the one worth staring at, because it is what you get when you send through the customer's mailbox over an API. Microsoft Graph's sendMail request body takes exactly two parameters, message and saveToSentItems. There is no envelope-sender field. Gmail's users.messages.send takes a message and sends it "to the recipients in the To, Cc, and Bcc headers" — again no envelope control. In both cases the platform, not your code, sets MAIL FROM. Neither page documents what it sets it to; in practice it is the mailbox address, which is observed behaviour rather than a documented guarantee. Either way you give up the return path.
Decknative sends this way and inherits this exact trade-off: replies come back through a Reply-To on our own MX, we never read the customer's inbox, and so an out-of-office reply lands with the customer rather than with us. Saying otherwise would mean asking for a restricted mailbox-read scope, which is a bigger ask than the problem is worth. The honest fix is on the sequence side, below.
What does a missed out-of-office cost?
Four things, in rough order of how much they hurt.
- Your follow-ups land while nobody is reading. Whatever cadence you designed — day 3, day 7, day 12 — collapses into a pile the lead sees all at once when they return.
- The lead’s first impression of you is that pile. Three unanswered messages read very differently in sequence than they do spread over two weeks.
- Your reporting lies. "No reply" gets recorded as disinterest when the true cause was absence, and that noise flows into whatever you use to judge which segments or subject lines are working.
- You spend send capacity and credits on a mailbox that is provably not being read, at a moment when you had a machine-readable signal telling you so.
And you usually get exactly one chance to catch the signal. Microsoft documents that "if automatic replies are enabled, only one reply is sent to each sender even if a recipient receives multiple messages from a sender" — the list of already-notified senders lives in the mailbox as OOF history. Gmail's vacation responder is similar but time-boxed: "In most cases, your reply is only sent to people the first time they message you," with a repeat if "the same person contacts you again after four days and your automatic reply is still on." Either way you cannot count on a second copy: on Microsoft the sender stays in the OOF history until the responder is toggled, and on Gmail a follow-up sent inside those four days gets nothing back.
Which headers mark a message as automatic?
One is standardised and several are folklore. Treat them accordingly.
| Header | Defined by | Values you will see | How much to trust it |
|---|---|---|---|
| Auto-Submitted | RFC 3834 §5 (Standards Track) | no, auto-generated, auto-replied | Normative. Anything other than "no" means automatic. |
| Precedence | No standard. Catalogued in RFC 2076 §3.9 as "Non-standard, controversial, discouraged". | bulk, junk, list (named in RFC 3834 §3.1.8); first-class (RFC 2076 §3.9) | Heuristic. RFC 3834 §2 explicitly declines to recommend any behaviour for it. |
| X-Auto-Response-Suppress | Microsoft [MS-OXCMAIL] Auto Response Suppress | None, All, DR, NDR, RN, NRN, OOF, AutoReply | Vendor-specific. It is a request to suppress responses, written by the sending client from the PidTagAutoResponseSuppress property. |
| X-Autoreply, X-Autorespond | Nothing. No RFC and no vendor specification we could find. | yes, or an arbitrary token | Folklore. Common enough to check for, never enough to decide on alone. |
| Return-Path: <> | RFC 5321 §4.5.5 | <> | Strong, not proof. Standards require notifications to use a null reverse-path; that does not make every null reverse-path a notification. |
RFC 3834's own rule for responders is the mirror image, and it is the rule you want on your side too: "Automatic responses SHOULD NOT be issued in response to any message which contains an Auto-Submitted header field (see below), where that field has any value other than 'no'."
A null return path deserves special mention because it is what both Microsoft and Exim document. Microsoft's own troubleshooting guidance notes, while explaining why a transport rule can eat out-of-office replies, that "OOF rules have a blank (<>) return path". Exim's autoreply transport documents the same: "messages created by the autoreply transport always have empty envelope sender addresses, like bounce messages", and it adds References and Auto-Submitted header lines, "constructed according to the rules in RFCs 2822 and 3834, respectively". So a conformant away message typically arrives from nobody, addressed to your envelope sender, carrying Auto-Submitted: auto-replied.
How do you classify one in code?
Check the normative header first and let everything else corroborate. This is about twenty lines against the Python standard library, and it is worth writing as a pure function over a raw message so you can test it against real captures.
import sys, email
m = email.message_from_binary_file(sys.stdin.buffer)
def get(h): return (m.get(h) or "").strip()
sigs = []
auto_sub = get("Auto-Submitted").split(";")[0].strip().lower()
if auto_sub and auto_sub != "no":
sigs.append(("Auto-Submitted", auto_sub, "rfc3834"))
if get("Precedence").lower() in ("bulk", "junk", "list"):
sigs.append(("Precedence", get("Precedence"), "heuristic"))
for h in ("X-Autoreply", "X-Autorespond", "X-Auto-Response-Suppress"):
if get(h):
sigs.append((h, get(h), "heuristic"))
if get("Return-Path") in ("<>", ""):
sigs.append(("Return-Path", get("Return-Path") or "(absent)", "heuristic"))
verdict = "AUTOMATIC" if any(s[2] == "rfc3834" for s in sigs) else \
"PROBABLY AUTOMATIC" if sigs else "HUMAN"
print(f"subject : {get('Subject')}")
print(f"verdict : {verdict}")
for name, val, basis in sigs:
print(f" signal: {name}: {val} [{basis}]")$ cat > oof.eml <<'EML'
Return-Path: <>
From: Lee Okafor <lead@example.net>
To: r+7f3a91@reply.example.com
Subject: Automatic reply: Quick question about your MSP stack
Auto-Submitted: auto-replied
X-Auto-Response-Suppress: All
I am out of the office until the 14th with limited access to email.
EML
$ cat > human.eml <<'EML'
Return-Path: <lead@example.net>
From: Lee Okafor <lead@example.net>
To: r+7f3a91@reply.example.com
Subject: Re: Quick question about your MSP stack
Sure, send over the details.
EML
$ python3 classify.py < oof.eml
subject : Automatic reply: Quick question about your MSP stack
verdict : AUTOMATIC
signal: Auto-Submitted: auto-replied [rfc3834]
signal: X-Auto-Response-Suppress: All [heuristic]
signal: Return-Path: <> [heuristic]
$ python3 classify.py < human.eml
subject : Re: Quick question about your MSP stack
verdict : HUMANTwo things not to do. Do not classify on the subject line: "Automatic reply", "Out of Office", "Abwesenheitsnotiz", "Réponse automatique" and a hundred others is a losing game, and a human writing "Re: out of office next week" will trip it. And do not treat an automatic response as a reply for the purposes of "halt the sequence on any reply". It is not an answer, it is not a rejection, and it is not interest. It is a fact about timing.
How do you actually capture them?
Three options, each with a real cost. Pick deliberately.
- Read the mailbox. It works, because the away message is sitting right there. It also means asking for a mailbox-read OAuth scope — gmail.readonly or Mail.Read — which is a materially bigger permission than send-only, with a correspondingly bigger review burden and a bigger ask of the customer.
- Control the envelope sender. If you relay the message yourself over SMTP, you set MAIL FROM, so you own the return path and the away message comes to you. The cost is that you are now the sending infrastructure, with all the alignment and reputation work that implies, instead of the customer’s own mailbox.
- Let the human catch it. The away message lands in the mailbox owner’s own inbox — not instantly, since Microsoft routes OOF replies through its high risk delivery pool “because OOF replies are lower-priority messages”, but it lands. A one-click "this lead is away until <date>" control in your UI turns a signal you cannot see into one keystroke from someone who can.
What is VERP, and where does it fit?
VERP — Variable Envelope Return Paths — is the general mechanism behind option two. Dan Bernstein described it in 1997: "each recipient of the message sees a different envelope sender address." The example in that document sends to God@heaven.af.mil with an envelope sender of djb-sos-owner-God=heaven.af.mil@silverton.berkeley.edu, so that whatever comes back — however uninformative — identifies the recipient in its own envelope.
That is exactly the trick you want for auto-replies, one layer down from where most tools apply it. Encode the thread key in MAIL FROM rather than in Reply-To, catch it on your own MX, and both classes of response — the human one and the machine one — arrive with the identifier attached. VERP was invented for bounces, but bounces and away messages travel the same road for the same reason. The catch, again, is that you can only do it if you own the envelope, which you do not when you send through someone else's mailbox API.
What should a sequence do when a lead is away?
Hold, do not cancel, and do not guess too hard.
- Hold the whole sequence for that lead, not just the next step. Shifting one send by a day just moves the pile.
- Prefer a fixed conservative push — say, seven or fourteen days — over parsing a return date out of the body. "Back on the 14th" is free-form prose in an unknown language and an unknown timezone, and a wrong parse resumes into the same empty chair.
- Do not re-score, re-draft, or re-qualify the lead. Nothing about the lead changed. Only the calendar did.
- Do not consume a credit or a send slot for the held step until it actually sends.
- Log the auto-reply against the thread so the eventual human reviewer sees why the gap exists.
- If a return date is parsed at all, show it to a person before acting on it.
None of this needs the away message to reach your server. It needs a way for the fact to reach your sequence — from your own MX if you own the envelope, or from the person who approved the draft in the first place. In a review-before-send workflow like Decknative's, that person is already in the loop on every message; the sequence just has to give them somewhere to put what they know.
Common questions
- Does an out-of-office reply ever go to the Reply-To address?
- Sometimes, but you cannot rely on it. RFC 3834 Section 4 says a responder SHOULD send to the Return-Path field and SHOULD NOT use Reply-To, and those are recommendations rather than absolute requirements. Non-conformant responders exist, so some auto-replies will reach a rewritten Reply-To address even though the specification directs them somewhere else.
- What is the difference between Return-Path and Reply-To?
- Return-Path is written by the receiving server from the SMTP MAIL FROM command, and RFC 5321 requires that it be used as the target for delivery error messages. Reply-To is an optional header the sender writes to suggest where humans should reply. One is envelope-level and guaranteed by protocol; the other is a hint in the message body that programs are told to ignore.
- Which header definitively identifies an automatic reply?
- Auto-Submitted, defined in RFC 3834 Section 5. Its values are "no", "auto-generated" and "auto-replied", and an away message should carry "auto-replied". Anything other than "no" means the message came from a program. Precedence, X-Autoreply and X-Autorespond are non-standard and should only ever corroborate a decision, never make one.
- Why is the Return-Path on an out-of-office reply empty?
- Because the responder does not want a reply to its reply. RFC 3834 Section 3.3 allows a MAIL FROM of <> for exactly this reason, and implementations follow it. Microsoft notes that OOF rules have a blank (<>) return path, and Exim documents that autoreply messages always have empty envelope sender addresses.
- Can I set a custom envelope sender when sending through Microsoft Graph or the Gmail API?
- No. Graph sendMail accepts only a message and a saveToSentItems flag, and Gmail send takes a message addressed by its To, Cc and Bcc headers. Neither exposes the SMTP envelope, so the platform sets MAIL FROM and you do not. That is why a conformant auto-reply goes to the sending mailbox rather than to your reply domain.
- Should an auto-reply halt a sequence the same way a human reply does?
- No. A human reply ends the sequence because the conversation has started. An auto-reply only says the recipient is temporarily absent, so the right response is to pause every remaining step for that lead and resume later. Treating it as a real reply loses the lead; ignoring it sends follow-ups into an empty inbox.
- Is VERP still worth implementing?
- It is worth implementing if you control the envelope sender, because it makes both bounces and auto-replies self-identifying without a lookup. Dan Bernstein described it in 1997 for mailing-list bounce handling, and the mechanism is unchanged: give every recipient a different MAIL FROM address that encodes who they are. If you send through someone else’s mailbox API you cannot use it, because you never set MAIL FROM.
Sources
- RFC 3834 — Recommendations for Automatic Responses to Electronic Mail
- RFC 5321 — Simple Mail Transfer Protocol (Sections 4.4 and 4.5.5, return path)
- RFC 2076 — Common Internet Message Headers (Section 3.9, Precedence)
- D. J. Bernstein — Variable Envelope Return Paths (1997)
- Microsoft Learn — Understand and troubleshoot Out of Office (OOF) replies
- Microsoft [MS-OXCMAIL] — Auto Response Suppress (X-Auto-Response-Suppress)
- Microsoft Graph — user: sendMail
- Gmail API — users.messages.send
- Exim specification — the autoreply transport
- Google Workspace Help — Send automatic replies (vacation responder)