SMTP FUTURERELEASE: HOLDUNTIL is Unix timestamp, should be RFC 3339

Issue Description

(please excuse multiple bugs in one report - say the word and I’ll post one topic each)

Stalwart’s implementation of the SMTP FUTURERELEASE extension appears to be incompatible with RFC 4865, primarily because HOLDUNTIL and the advertised maximum future-release date are represented as Unix timestamps rather than RFC 3339 date-times.

RFC 4865, including verified Erratum 2040, defines:

HOLDFOR=<seconds>
HOLDUNTIL=<date-time>

where date-time uses the RFC 3339 format.

For example:

MAIL FROM:<[email protected]> HOLDUNTIL=2026-08-10T03:00:00Z

Stalwart instead expects HOLDUNTIL to contain an integer Unix timestamp.

There are also several related validation issues:

  • A MAIL FROM command containing both HOLDFOR and HOLDUNTIL is accepted, although RFC 4865 requires more than one hold parameter to be rejected.
  • A HOLDUNTIL timestamp in the past is converted to a zero-second hold using saturating subtraction and accepted for immediate delivery.
  • The EHLO FUTURERELEASE capability advertises its maximum date as a Unix timestamp rather than an RFC 3339 date-time.

Relevant specification:

https://www.rfc-editor.org/rfc/rfc4865.html

Verified Erratum 2040:

Expected Behavior

A client should be able to submit an RFC 3339 timestamp:

MAIL FROM:<[email protected]> HOLDUNTIL=2026-08-10T03:00:00Z

The EHLO capability should similarly advertise the maximum supported absolute date as an RFC 3339 timestamp, for example:

250-FUTURERELEASE 86400 2026-08-10T03:00:00Z

Actual Behavior

Stalwart currently treats HOLDUNTIL as Unix epoch seconds.

For example, its SMTP tests construct values equivalent to:

MAIL FROM:<[email protected]> HOLDUNTIL=1786321200

and expect them to succeed.

The SMTP parser parses HOLDUNTIL using the same numeric parser used for integer parameters, so a standards-compliant RFC 3339 timestamp cannot be parsed.

The EHLO response also advertises the maximum absolute release time as Unix seconds:

250-FUTURERELEASE 86400 1786407600

rather than an RFC 3339 date-time.

Reproduction Steps

  1. Enable the FUTURERELEASE SMTP extension, for example with a maximum hold duration of one day.

  2. Connect to the submission service and issue EHLO.

  3. Observe the advertised capability. Stalwart returns a response similar to:

250-FUTURERELEASE 86400 1786407600

The second argument is a Unix timestamp rather than the RFC 3339 date-time required by RFC 4865.

  1. Attempt a standards-compliant HOLDUNTIL request:
MAIL FROM:<[email protected]> HOLDUNTIL=2026-08-10T03:00:00Z
  1. Observe that Stalwart rejects it because HOLDUNTIL is parsed as an integer.

  2. Send the equivalent Unix timestamp instead:

MAIL FROM:<[email protected]> HOLDUNTIL=1786321200
  1. Observe that Stalwart accepts it.

  2. As a separate validation test, send both hold parameters:

MAIL FROM:<[email protected]> HOLDFOR=3600 HOLDUNTIL=1786321200
  1. Observe that the command is accepted rather than rejected.

Relevant Log Output

Nothing relevant.

Stalwart Version

v0.16.x

Installation Method

Docker

Database Backend

RocksDB

Blob Storage

RocksDB

Search Engine

Internal

Directory Backend

Internal

I have reviewed the documentation and FAQ and confirm that my issue is NOT addressed there.

on

I have searched this support forum (open and closed topics) and confirm this is not a duplicate.

on

I understand that topics in this category are triaged by a bot first but a human reply will follow up. If I’d prefer a human-only reply, I’ll add the no-ai tag to my topic.

on

Your analysis matches what’s in the source. Stalwart’s MAIL FROM parser treats HOLDUNTIL as a plain integer (parsed the same way as HOLDFOR), converts it via a saturating subtraction against the current Unix time (from.hold_until.saturating_sub(now)), and the EHLO capability line for FUTURERELEASE is built from that same numeric max-hold duration rather than an RFC 3339 date-time. There’s also no check preventing both HOLDFOR and HOLDUNTIL from being supplied together, code only branches on from.hold_for != 0.

None of the current docs (the MtaExtensions.futureRelease reference or the SMTP extensions guide) describe this as intentional, they only document the configurable max-hold duration, not the wire format. So this does appear to be a genuine RFC 4865 non-compliance in the current implementation rather than a documented design choice. A staff member will need to confirm whether/when this gets addressed.

This is an automated reply from the Stalwart Help Bot. Other community members may follow up if this answer is incomplete or wrong.

Fixed in v0.16.17 (yet to be released).