# OutboundPolicy for notifications is hard-coded to \`OutboundPolicy::PublicOnly\`

**URL:** https://support.stalw.art/t/outboundpolicy-for-notifications-is-hard-coded-to-outboundpolicy-publiconly/2151
**Category:** Issues
**Created:** [October 30, 2026, 10:48pm UTC](https://support.stalw.art/t/outboundpolicy-for-notifications-is-hard-coded-to-outboundpolicy-publiconly/2151 "2026-10-30T22:48:01Z")
**Posts on this page:** 3
**Page:** 1

<div class="post-metadata">

### Author: ![Jim](https://support.stalw.art/letter_avatar_proxy/v4/letter/j/ac91a4/32.png) [@Jim](https://support.stalw.art/u/Jim)
#### Post date: [October 30, 2026, 10:48pm UTC](https://support.stalw.art/t/outboundpolicy-for-notifications-is-hard-coded-to-outboundpolicy-publiconly/2151/1 "2026-10-30T22:48:01Z")

</div>

### Issue Description

I’m running Stalwart on a server on an internal network with several other services accessible using split DNS, including ntfy, for push notifications.

Stalwart allows registrations but doesn’t send any notifications. As best I can tell, this is because the HTTP client used to send them [is hard-coded to `OutboundPolicy::PublicOnly`](https://github.com/stalwartlabs/stalwart/blob/23b69755cb3cd8ecd952fe0443c5ac067a506184/crates/services/src/state_manager/http.rs#L262), which results in internal IP addresses being discarded, which is problematic because my notification server has an internal IP address.

To confirm, I ran the server with the following patch applied. When I did, push notifications worked correctly.

```patch
diff --git a/crates/jmap/src/push/set.rs b/crates/jmap/src/push/set.rs
index c8e7484c..574052c4 100644
--- a/crates/jmap/src/push/set.rs
+++ b/crates/jmap/src/push/set.rs
@@ -425,7 +425,7 @@ fn validate_push_value(
 }

 fn validate_push_url(url: &str) -> Result<(), OutboundError> {
- OutboundPolicy::PublicOnly.parse_url(url).map(|_| ())
+ OutboundPolicy::Trusted.parse_url(url).map(|_| ())
 }

 fn parse_email_push(
diff --git a/crates/services/src/state_manager/http.rs b/crates/services/src/state_manager/http.rs
index bb9f5242..1b825932 100644
--- a/crates/services/src/state_manager/http.rs
+++ b/crates/services/src/state_manager/http.rs
@@ -259,7 +259,7 @@ async fn post_object(
 pub(crate) fn build_push_client() -> OutboundClient {
     OutboundClient::new(
         utils::http::http_client_builder(cfg!(stalwart_tests)),
- OutboundPolicy::PublicOnly,
+ OutboundPolicy::Trusted,
         Redirects::SameOrganization(MAX_REDIRECTS),
     )
 }

```

### Expected Behavior

`OutboundPolicy::PublicOnly` is configurable. When not used, notifications to an internal IP succeed.

### Actual Behavior

`OutboundPolicy` is not configurable. Notifications to an internal IP are blocked.

### Reproduction Steps

1. Set up ntfy on an internal server with split DNS.
2. Register a client for notifications using ntfy
3. Trigger something that results in a notification.

### Relevant Log Output

```auto
2026-10-30T20:55:46Z DEBUG Push subscription error (push-subscription.error) details = "HTTP POST failed", url = "<url>", reason = "error sending request for url (<url>)"

```

### Stalwart Version

v1.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

---

<div class="post-metadata">

### Author: ![helpbot](https://support.stalw.art/user_avatar/support.stalw.art/helpbot/32/13_2.png) [@helpbot](https://support.stalw.art/u/helpbot)
#### Post date: [October 30, 2026, 10:48pm UTC](https://support.stalw.art/t/outboundpolicy-for-notifications-is-hard-coded-to-outboundpolicy-publiconly/2151/2 "2026-10-30T22:48:09Z")

</div>

Your reading is correct, and it’s documented behaviour. I found no setting that changes it.

Stalwart accepts a push subscription only for a public `https` URL. A URL is refused if it uses another scheme, contains credentials, or has a host that is private, loopback or otherwise non-public. The docs say the same check is applied again when notifications are sent. So a name that resolves to an internal address through split DNS won’t receive notifications, even if the subscription was accepted. This matches what your patch shows: the restriction is applied at both validation and send time, and neither place has a configuration option.

Until the policy becomes configurable, there are two workarounds I can see in the docs:

- Expose ntfy on a public address with `https`.
- Keep running your patched build.

I found no documented setting for allowing internal destinations. Making the policy configurable would be a feature request, and a human will follow up here.

Docs: [Push notifications | Stalwart](https://stalw.art/docs/http/jmap/push)

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

---

<div class="post-metadata">

### Author: ![Jim](https://support.stalw.art/letter_avatar_proxy/v4/letter/j/ac91a4/32.png) [@Jim](https://support.stalw.art/u/Jim)
#### Post date: [October 30, 2026, 10:56pm UTC](https://support.stalw.art/t/outboundpolicy-for-notifications-is-hard-coded-to-outboundpolicy-publiconly/2151/3 "2026-10-30T22:56:16Z")

</div>

Regarding the documented behaviour:

> A URL with another scheme, a URL with credentials, and a URL whose host is a private, loopback or otherwise non-public address or name are refused with `invalidProperties` on `url`, with a description such as `URL must use the https scheme` or `Destination is a local or reserved IP address`.

This does not seem to be the case. At no point do I see an error like this, I only see “HTTP POST failed”.
