No failure notice when sending to a non existing mailbox on local domain

Issue Description

When sending an email using JMAP (tested with Bulwark webmail and sterna) to a non existing mailbox on the local domain (eg from [email protected] to [email protected]), there’s no failure notice indicating the email was not delivered

Expected Behavior

As the sender, I should be notified somehow (either at submission time, or through a failure notice email) that my email wasn’t delivered

Actual Behavior

The email is silently lost. Only stalwart logs show the email was not delivered

Reproduction Steps

  1. Configure stalwart with a local domain
  2. Using a JMAP client, try to send an email from a valid account to a non existing mailbox on the same domain

Relevant Log Output

Stalwart logs show the email is not delivered

2026-08-27T09:51:46Z INFO Message appended via JMAP (message-ingest.jmap-append) listenerId = "http", localPort = 8877, remoteIp = 127.0.0.1, remotePort = 46284, accountId = 66, documentId = 192, mailboxId = [3], blobId = "bfd88e27507bab7414926329aac8b31c9bff6cdb4ef70f8b45775faeda355396", changeId = 620, messageId = "18cfa0bc134c1af6.6f8db0bc3cdea1d5.fc2c09f495823eb7@11a5ee146cfd", size = 311, elapsed = 50ms 
2026-08-27T09:51:50Z INFO Message appended via JMAP (message-ingest.jmap-append) listenerId = "http", localPort = 8877, remoteIp = 127.0.0.1, remotePort = 46960, accountId = 66, documentId = 193, mailboxId = [3], blobId = "96688918b340ef9484ddee79edf2897c9b0f3e414537d3db830d4c454fec7677", changeId = 621, messageId = "18cfa0bcdfa33d82.c46bfca662aa3776.941006569d3391b@11a5ee146cfd", size = 679, elapsed = 29ms 
2026-08-27T09:51:50Z INFO Message appended via JMAP (message-ingest.jmap-append) listenerId = "http", localPort = 8877, remoteIp = 127.0.0.1, remotePort = 46284, accountId = 66, documentId = 194, mailboxId = [3], blobId = "50df71f11b0548e6d8753b8409c855f4f846be18f622414b1c230fc7bac8e950", changeId = 623, messageId = "[email protected]", size = 689, elapsed = 36ms 
2026-08-27T09:51:50Z INFO SMTP MAIL FROM command (smtp.mail-from) from = "[email protected]" 
2026-08-27T09:51:50Z INFO Mailbox does not exist (smtp.mailbox-does-not-exist) to = "[email protected]" 

### Stalwart Version
v0.16.x

### Installation Method
Binary (Linux)

### Database Backend
PostgreSQL

### Blob Storage
PostgreSQL

### Search Engine
PostgreSQL

### Directory Backend
OIDC

### Additional Context
Running stalwart 0.16.19
Haven't tried with a more standard IMAP+SMTP client yet, but I'd like to use JMAP anyway

### 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

Stalwart does report this failure, but not as a bounce message in the mailbox: it is surfaced through the deliveryStatus property of the EmailSubmission object created by the EmailSubmission/set call.

When you submit a message over JMAP, Stalwart runs a local SMTP session synchronously (MAIL FROM / RCPT TO / DATA) as part of the EmailSubmission/set call. If a recipient is rejected at RCPT TO time (as happens here, since the mailbox doesn’t exist), the message is never queued at all, so no DSN/bounce email is generated by the queue manager, because the message never entered the queue. Instead, the rejection reason (e.g. the 550 5.1.2 Mailbox does not exist SMTP reply) is recorded per-recipient in the submission’s deliveryStatus map with delivered: "no" and the raw SMTP reply text. A JMAP client is expected to fetch this via EmailSubmission/get (or watch it via push/state changes) to know whether the send failed, since RFC 8621 defines deliveryStatus for exactly this purpose. If Bulwark or Sterna aren’t checking/displaying deliveryStatus after submission, that’s a client-side gap rather than a missing notification from the server.

For deliveries that fail after being accepted into the queue (e.g. a temporary local delivery failure, or any SMTP-inbound message to a nonexistent local address), Stalwart does generate a full DSN bounce, as described in the delivery notifications docs: Delivery Notifications | Stalwart

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

Here’s a submission using bulwark

Request payload
{
  "using": [
    "urn:ietf:params:jmap:core",
    "urn:ietf:params:jmap:mail",
    "urn:ietf:params:jmap:submission"
  ],
  "methodCalls": [
    [
      "Email/set",
      {
        "accountId": "cc",
        "create": {
          "send-1788034242527": {
            "from": [
              {
                "name": "Daniel Berteaud",
                "email": "[email protected]"
              }
            ],
            "to": [
              {
                "email": "[email protected]"
              }
            ],
            "subject": "test",
            "messageId": [
              "[email protected]"
            ],
            "keywords": {
              "$seen": true,
              "$draft": true
            },
            "mailboxIds": {
              "d": true
            },
            "bodyValues": {
              "text": {
                "value": "test"
              },
              "html": {
                "value": "<div><p dir=\"auto\">test</p></div>"
              }
            },
            "textBody": [
              {
                "partId": "text",
                "type": "text/plain"
              }
            ],
            "htmlBody": [
              {
                "partId": "html",
                "type": "text/html"
              }
            ]
          }
        }
      },
      "0"
    ],
    [
      "EmailSubmission/set",
      {
        "accountId": "cc",
        "create": {
          "1": {
            "emailId": "#send-1788034242527",
            "identityId": "k"
          }
        },
        "onSuccessUpdateEmail": {
          "#1": {
            "mailboxIds": {
              "e": true
            },
            "keywords/$draft": null
          }
        }
      },
      "1"
    ]
  ]
}

And here’s the reply from stalwart

Response payload
{
    "methodResponses": [
        [
            "Email/set",
            {
                "accountId": "cc",
                "oldState": "sqycq",
                "newState": "sq2cq",
                "created": {
                    "send-1788034242527": {
                        "id": "zmaaaagl",
                        "threadId": "gl",
                        "blobId": "cari2c2q1ksdwyyolnspv3nj2bueoeqq01xkiqnw0ovxay9pzhdboqqazmaq",
                        "size": 683
                    }
                }
            },
            "0"
        ],
        [
            "EmailSubmission/set",
            {
                "accountId": "cc",
                "newState": "sracq",
                "created": {
                    "1": {
                        "id": "bz",
                        "sendAt": "2026-08-29T20:10:42Z",
                        "undoStatus": "final"
                    }
                }
            },
            "1"
        ],
        [
            "Email/set",
            {
                "accountId": "cc",
                "oldState": "sq2cq",
                "newState": "srecq",
                "updated": {
                    "zmaaaagl": null
                }
            },
            "1"
        ]
    ],
    "sessionState": "fb6ee943"
}

Maybe I’m missing something but I see no deliveryStatus here

OK, the deliveryStatus can be found on a later EmailSubmission/get request. I’ll open a bug on bulwark then

I’ve opened bugs against bulwark and sterna-mail