Calendar iMIP/iTIP auto-add requires DMARC pass — DKIM-pass-only senders are silently skipped

Issue Description

The iMIP/iTIP inbound auto-add path requires is_sender_authenticated
to be true, which is hard-coded to require a strict
DmarcResult::Pass. Senders whose domain has no DMARC record published
— but whose messages still authenticate via DKIM (e.g. ordinary Google
Workspace tenants that only published Google’s recommended SPF and DKIM
but did not publish a DMARC TXT record) — are silently skipped by the
iTIP processor. The invitation is delivered to the inbox as a plain
message but never inserted into the recipient’s CalDAV calendar, even
with calendar.scheduling.inbound.auto-add = true.

This is stricter than how Gmail, Outlook, and most other mail providers
treat the same messages — they accept DKIM-pass as sufficient
authentication for iMIP auto-processing. As a result, Stalwart fails to
interoperate with a large slice of real-world Google Workspace senders
who follow Google’s default setup.

Source references for v0.15.5:

  • crates/smtp/src/inbound/data.rs:716dmarc_pass is computed
    strictly: dmarc_result.is_some_and(|r| r == DmarcResult::Pass). No
    other auth path sets the flag.
  • crates/smtp/src/outbound/local.rs:45sender_authenticated is
    then (FROM_UNAUTHENTICATED_DMARC | FROM_AUTHENTICATED) != 0.
  • crates/email/src/message/ingest.rs:350 — iTIP processor is gated on
    is_sender_authenticated. The processor is skipped silently when
    this is false; no log line is emitted indicating the iMIP part was
    seen but rejected.
  • crates/groupware/src/calendar/itip.rs:281itip_auto_add only
    loosens the address-book check, not the upstream auth gate.

Expected Behavior

Either (a) calendar.scheduling.inbound.auto-add = true could relax
the DMARC requirement so that DKIM-pass is sufficient, matching
Gmail/Outlook behavior; or (b) a new, distinct knob is added — e.g.
calendar.scheduling.inbound.require-dmarc-pass = false /
inbound.accept-dkim-only = true — that an operator can opt in to.
The current auto-add documentation suggests it broadly relaxes the
inbound gate; the actual scope is narrower (address-book only) which
is surprising.

Additionally, when the iTIP path is skipped due to the auth gate, it
would be very helpful to emit an INFO-level log line so operators
can diagnose “why didn’t this invitation auto-add?” without having to
read the source.

Actual Behavior

iMIP invitation from a real Google Workspace tenant
(<user>@<workspace-domain>) — DKIM passes for both google.com and
<workspace-domain>-fi.<date>.gappssmtp.com, but DMARC fails with
result = No DMARC record (dmarc.none) because the tenant has not
manually published _dmarc. Stalwart delivers the message to the
inbox and does nothing else. The recipient’s /dav/cal/<user>/default/
is not touched. No log line indicates that iTIP processing was even
considered. The recipient’s native CalDAV client (Fantastical, Apple
Calendar, Thunderbird Lightning) shows no RSVP UI because there is no
calendar object to act on.

Even setting calendar.scheduling.inbound.auto-add = true has no
effect on this path.

Reproduction Steps

  1. Fresh Stalwart v0.15.5 instance with
    calendar.scheduling.inbound.auto-add = true in config.toml.
  2. Verify the setting is effective:
    curl -u admin:$PW http://127.0.0.1:8080/api/settings/list?prefix=calendar.scheduling
    returns inbound.auto-add: true.
  3. Send a Google Calendar invitation from a Workspace tenant whose
    primary domain has no _dmarc TXT record. (Most Workspace tenants
    who followed only Google’s default DNS setup wizard are in this
    state — Google does not publish _dmarc by default.)
  4. Observe in the Stalwart log: DKIM verification passed and
    DMARC check failed ... No DMARC record (dmarc.none).
  5. Observe that the message is delivered to the inbox
    (message-ingest.ham ... mailboxId = [0]) but no
    ItipMessageReceived event is logged.
  6. PROPFIND on /dav/cal/<recipient>/default/ confirms no new event
    was inserted.

Relevant Log Output

2026-05-27T06:39:31Z INFO DKIM verification passed (smtp.dkim-pass) ... result = [DKIM verification passed (dkim.pass) { domain = "google.com" }, DKIM verification passed (dkim.pass) { domain = "<workspace>.gappssmtp.com" }]
2026-05-27T06:39:31Z INFO DMARC check failed (smtp.dmarc-fail) ... domain = "<workspace-domain>", policy = "none", result = No DMARC record (dmarc.none)
2026-05-27T06:39:31Z INFO Queued message for delivery ... from = "<user>@<workspace-domain>", to = ["<recipient>@<our-domain>"], size = 38415
2026-05-27T06:39:31Z INFO Message ingested (message-ingest.ham) ... accountId = 6, documentId = 8, mailboxId = [0]
# expected but missing: ItipMessageReceived / ItipMessageError event

Stalwart Version

v0.15.x

Installation Method

Docker

Database Backend

RocksDB

Blob Storage

RocksDB

Search Engine

Internal

Directory Backend

Internal

Additional Context

  • Same domain works for the same recipient on Gmail/Outlook — those
    servers’ iMIP processors do not require DMARC pass and accept
    DKIM-pass as sufficient.
  • Reproduced both with the sender’s domain having no _dmarc record
    and verified manually that adding
    _dmarc.<domain> TXT "v=DMARC1; p=none" to the sender’s DNS makes
    the auto-add work end-to-end on the same Stalwart instance —
    proving the gate is the only blocker, the rest of the pipeline is
    healthy.
  • Use case: small business mail server, ~5 mailboxes, native CalDAV
    (Fantastical, Apple Calendar) is the primary client. Auto-add is
    the only practical path — manually opening .ics attachments and
    replying via Roundcube is fine as a fallback but defeats the value
    of running a CalDAV server.
  • We are willing to contribute a PR if the maintainers can agree on
    the preferred config-knob name and scope.

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

Let me look at the relevant source code to verify the claims and understand the current implementation.

The analysis in this report is accurate and well-grounded in the source code. Here is a confirmation of the findings and the current workaround.


Your analysis is correct. The source code confirms exactly what you’ve described:

The authentication gate for iTIP/iMIP processing is strictly DMARC pass. In crates/smtp/src/inbound/data.rs, dmarc_pass is set only when dmarc_result == DmarcResult::Pass. This flag propagates as FROM_UNAUTHENTICATED_DMARC, and in crates/smtp/src/outbound/local.rs, sender_authenticated is (FROM_UNAUTHENTICATED_DMARC | FROM_AUTHENTICATED) != 0. In crates/email/src/message/ingest.rs the entire iMIP block is gated on is_sender_authenticated, with no log emitted when the gate is not passed.

The docs confirm the design intent (DMARC pass + address book = default auto-add), but also document a full bypass: setting autoAddInvitations to true on the CalendarScheduling singleton. Per the docs:

With that setting enabled, Stalwart accepts all valid iTIP and iMIP invitations without verifying the sender’s authenticity or presence in the address book.

Immediate workaround: In the WebUI, navigate to Settings > Collaboration > Calendar Scheduling and set autoAddInvitations = true. This bypasses both the DMARC check and the address-book check entirely. The docs do warn this should be used with caution in open/federated environments, as it opens the door to calendar spam.

What the docs don’t currently offer is the granular middle ground you’re requesting: “accept DKIM-pass as sufficient, without requiring a published DMARC record.” That is a valid interoperability gap - dmarc.none (no record published) is treated identically to dmarc.fail (record exists, message failed), which is stricter than Gmail/Outlook. Your two proposed options (loosening the check when auto-add is on, or adding a separate require-dmarc-pass knob) and the request for a log line when the iTIP gate is skipped are both well-reasoned feature requests. A human maintainer will need to weigh in on the preferred approach and config-knob name.

The docs page for reference: https://stalw.art/docs/collaboration/scheduling

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

Thanks for the source-code-grounded confirmation.

I want to flag a discrepancy with the suggested workaround and I’d like a human maintainer to weigh in on whether the docs or the code is authoritative here.

The autoAddInvitations / calendar.scheduling.inbound.auto-add = true workaround does not actually bypass the DMARC gate in v0.15.5.

I’ve had that setting enabled in production since I first opened this issue (verified live: calendar.scheduling.inbound.auto-add = true is the only calendar.scheduling.* key set, and I see no separate autoAddInvitations key — I believe they’re the same setting under the camelCase WebUI label vs. the dotted TOML key, but happy to be corrected). The DMARC-failing Google Workspace invitation that motivated the report still does not reach CalDAV with that setting on.

Reading the source again, this matches what I’d expect:

  • crates/groupware/src/calendar/itip.rs:281itip_auto_add is consulted inside the iTIP processor, and only loosens the address-book lookup.
  • crates/email/src/message/ingest.rs:350 — the iTIP processor itself is gated on is_sender_authenticated upstream of any itip_auto_add check. If that gate is false, the processor never runs and itip_auto_add has no opportunity to take effect.

So either:

  1. The docs overstate the scope of autoAddInvitations — it loosens the address-book check but not the auth gate, in which case the docs page ( Scheduling | Stalwart ) could be clarified; or
  2. There’s a second, distinct setting I haven’t found that does the full bypass the docs describe — in which case I’d love a pointer to the config key.

Empirically, option (1) matches the behaviour I see. If that’s correct, then the feature request (loosen the gate to accept DKIM-pass when dmarc.none, or add a separate require-dmarc-pass = false knob) really is the only path forward for interop with default-config Google Workspace senders.

Happy to contribute a PR once a maintainer indicates the preferred knob name and scope.

This is expected behaviour, senders must pass DMARC for auto-add to work.

This something that Google or Microsoft does not require. This is something that at least Google Workspace does not provide. To require it, renders invites from wide number of compleately legimate businesses invalid. Because of this, from a business perspective, Stalwart is not a reasonable option for email and calendars, if this behaviour is not changed.

Please reconsider. We really would like to use this and are maing here an extra effort to get it working. Be aware that in my business, there are normal people that just want to use calendar. From their perspective, if the calendar does not accept invites from Business using Google Workspace, it means that it is broken.

A DKIM pass is enough for a DMARC pass.

I think there is a misunderstanding.

DMARC requires alignment, not just any DKIM pass. Per RFC 7489 §3.1, a DMARC pass requires that either SPF or DKIM passes and that the authenticated identifier aligns with the From: header domain (DKIM d= aligning with From: domain, or SPF MAIL FROM domain aligning). A DKIM signature that validates on an unrelated domain does not produce a DMARC pass.

In our reproduction the DKIM signatures on the Google Workspace invitation are:

  • d=google.com
  • d=<workspace>-fi.<date>.gappssmtp.com

Neither aligns with the From: header domain <user>@<workspace-domain>. So even though DKIM passes, DMARC cannot pass. Stalwart’s own log on the same message confirms this:

DMARC check failed (smtp.dmarc-fail) ... domain = "<workspace-domain>", result = No DMARC record (dmarc.none)

The iTIP processor is then silently skipped. calendar.scheduling.inbound.auto-add = true has been on in production since we filed this issue (verified via the settings API) and does not change this because auto-add only loosens the address-book check inside the processor (crates/groupware/src/calendar/itip.rs:281), while the auth gate is upstream of it at crates/email/src/message/ingest.rs:350.

So concretely: the message that motivated this issue is a perfectly ordinary Google Workspace invitation. Gmail and Outlook accept it into the recipient’s calendar. Stalwart does not, and no operator-visible setting changes that. The only thing that did change the outcome was manually publishing a _dmarc TXT record on the sender’s domain, something we cannot ask every business partner to do.

Could you confirm whether you intend auto-add to bypass the auth gate (in which case there is a bug, since it doesn’t), or whether a separate knob is needed (e.g. inbound.accept-dkim-only / inbound.require-dmarc-pass = false)? Once the preferred shape is agreed I’m happy to send a PR.

We really would like to use Stalwart for both mail and calendars in production. From the perspective of an ordinary end-user, a calendar that silently drops invitations from a large fraction of legitimate Google Workspace senders looks broken.

There are companies that specialise in sending calendar spam, DMARC pass is a requirement.

If the remote system does not pass DMARC it is broken and the fix should not be relaxing Stalwart’s security verification. Even if the domain is hosted at Google, it can still be misconfigured. If you are experiencing this issue with all domains then the misconfiguration is probably at your side and should be evident in the log files.

I understand the threat model and I’m not asking the default to change.

Google and Microsoft accept these invitations without complaint. That makes their behavior the de-facto standard, regardless of the spec. When a Google invitation reaches our Stalwart mailbox and silently doesn’t show up, the customer concludes our server is broken, not theirs. I cannot ask every business partner to audit their DNS so our self-hosted server will accept their invitations.

So the practical ask is just an opt-in operator knob, off by default. Strict deployments leave it off; operators who need to interoperate with the real installed base turn it on, accepting the tradeoff knowingly.

Without that escape hatch, Stalwart cannot realistically replace Google/Microsoft for business mail.

As I said before, this is configuration problem. There are no issues receiving iMIP messages from Google/Microsoft or any other senders that pass DMARC. If DMARC is not passing for Google/Microsoft please check both the server logs and also the spam filter headers, in case these are landing in the junk folder.

This is not a configuration problem. Stalwart’s own log on the failing message:

DMARC check failed (smtp.dmarc-fail) ... result = No DMARC record (dmarc.none)

The sender is a Google Workspace customer domain, not google.com. Google does not publish _dmarc for customer domains — from Google’s own admin help:

“You don’t need to do anything in your Google Admin console to set up DMARC. Instead… log into your domain host and add the DMARC record.”

Most customers haven’t. Even among the top 1.8M global domains (Fortune 500 + Inc. 5000), only 47.7% have published DMARC (EasyDMARC 2025); SMB adoption is lower. So DKIM passes, DMARC returns dmarc.none, and Stalwart silently skips the iTIP processor. Gmail and Outlook accept the same message into the calendar. Not in the junk folder, not a spam-filter artefact.

The gate is doing exactly what the code says (is_sender_authenticated requires DmarcResult::Pass). That is the behavior we are asking to make opt-in-relaxable.

That is correct, Stalwart requires DMARC alignment and this should not be an issue with most remote systems. If there is no DMARC alignment then the Google Workspace customer has a configuration problem.
This won’t be changed in Stalwart as it will open the gate to calendar spam. If you need to disable DMARC checks for iMIP you will have to run a custom Stalwart build unfortunately.