ntfy/docs/publish.md

532 lines
19 KiB
Markdown
Raw Normal View History

2021-12-02 05:08:12 +01:00
# Publishing
2021-12-04 02:38:21 +01:00
Publishing messages can be done via HTTP PUT or POST. Topics are created on the fly by subscribing or publishing to them.
Because there is no sign-up, **the topic is essentially a password**, so pick something that's not easily guessable.
2021-12-02 05:08:12 +01:00
Here's an example showing how to publish a simple message using a POST request:
2021-12-04 02:38:21 +01:00
2021-12-02 05:08:12 +01:00
=== "Command line (curl)"
```
curl -d "Backup successful 😀" ntfy.sh/mytopic
```
=== "HTTP"
``` http
POST /mytopic HTTP/1.1
Host: ntfy.sh
Backup successful 😀
```
=== "JavaScript"
``` javascript
fetch('https://ntfy.sh/mytopic', {
method: 'POST', // PUT works too
body: 'Backup successful 😀'
})
```
=== "Go"
``` go
http.Post("https://ntfy.sh/mytopic", "text/plain",
strings.NewReader("Backup successful 😀"))
```
=== "PHP"
2021-12-04 02:38:21 +01:00
``` php-inline
2021-12-02 05:08:12 +01:00
file_get_contents('https://ntfy.sh/mytopic', false, stream_context_create([
'http' => [
'method' => 'POST', // PUT also works
'header' => 'Content-Type: text/plain',
'content' => 'Backup successful 😀'
]
]));
```
2021-12-02 23:27:31 +01:00
If you have the [Android app](subscribe/phone.md) installed on your phone, this will create a notification that looks like this:
2021-12-02 05:08:12 +01:00
<figure markdown>
2021-12-12 20:26:24 +01:00
![basic notification](static/img/android-screenshot-basic-notification.png){ width=500 }
2021-12-02 05:08:12 +01:00
<figcaption>Android notification</figcaption>
</figure>
There are more features related to publishing messages: You can set a [notification priority](#message-priority),
2021-12-09 16:23:17 +01:00
a [title](#message-title), and [tag messages](#tags-emojis) 🥳 🎉. Here's an example that uses some of them at together:
2021-12-02 05:08:12 +01:00
=== "Command line (curl)"
```
curl \
-H "Title: Unauthorized access detected" \
-H "Priority: urgent" \
-H "Tags: warning,skull" \
-d "Remote access to phils-laptop detected. Act right away." \
ntfy.sh/phil_alerts
```
=== "HTTP"
``` http
POST /phil_alerts HTTP/1.1
Host: ntfy.sh
Title: Unauthorized access detected
Priority: urgent
Tags: warning,skull
Remote access to phils-laptop detected. Act right away.
```
=== "JavaScript"
``` javascript
fetch('https://ntfy.sh/phil_alerts', {
method: 'POST', // PUT works too
body: 'Remote access to phils-laptop detected. Act right away.',
headers: {
'Title': 'Unauthorized access detected',
'Priority': 'urgent',
'Tags': 'warning,skull'
}
})
```
=== "Go"
``` go
req, _ := http.NewRequest("POST", "https://ntfy.sh/phil_alerts",
strings.NewReader("Remote access to phils-laptop detected. Act right away."))
req.Header.Set("Title", "Unauthorized access detected")
req.Header.Set("Priority", "urgent")
req.Header.Set("Tags", "warning,skull")
http.DefaultClient.Do(req)
```
=== "PHP"
2021-12-04 02:38:21 +01:00
``` php-inline
2021-12-02 05:08:12 +01:00
file_get_contents('https://ntfy.sh/phil_alerts', false, stream_context_create([
'http' => [
'method' => 'POST', // PUT also works
'header' =>
"Content-Type: text/plain\r\n" .
"Title: Unauthorized access detected\r\n" .
"Priority: urgent\r\n" .
"Tags: warning,skull",
'content' => 'Remote access to phils-laptop detected. Act right away.'
]
]));
```
<figure markdown>
2021-12-02 23:27:31 +01:00
![priority notification](static/img/priority-notification.png){ width=500 }
2021-12-02 05:08:12 +01:00
<figcaption>Urgent notification with tags and title</figcaption>
</figure>
2021-12-02 18:04:22 +01:00
## Message title
The notification title is typically set to the topic short URL (e.g. `ntfy.sh/mytopic`). To override the title,
you can set the `X-Title` header (or any of its aliases: `Title`, `ti`, or `t`).
=== "Command line (curl)"
```
curl -H "X-Title: Dogs are better than cats" -d "Oh my ..." ntfy.sh/controversial
curl -H "Title: Dogs are better than cats" -d "Oh my ..." ntfy.sh/controversial
curl -H "t: Dogs are better than cats" -d "Oh my ..." ntfy.sh/controversial
```
=== "HTTP"
``` http
POST /controversial HTTP/1.1
Host: ntfy.sh
Title: Dogs are better than cats
Oh my ...
```
=== "JavaScript"
``` javascript
fetch('https://ntfy.sh/controversial', {
method: 'POST',
body: 'Oh my ...',
headers: { 'Title': 'Dogs are better than cats' }
})
```
=== "Go"
``` go
req, _ := http.NewRequest("POST", "https://ntfy.sh/controversial", strings.NewReader("Oh my ..."))
req.Header.Set("Title", "Dogs are better than cats")
http.DefaultClient.Do(req)
```
=== "PHP"
2021-12-04 02:38:21 +01:00
``` php-inline
2021-12-02 18:04:22 +01:00
file_get_contents('https://ntfy.sh/controversial', false, stream_context_create([
'http' => [
'method' => 'POST',
'header' =>
"Content-Type: text/plain\r\n" .
"Title: Dogs are better than cats",
'content' => 'Oh my ...'
]
]));
```
<figure markdown>
2021-12-02 23:27:31 +01:00
![notification with title](static/img/notification-with-title.png){ width=500 }
2021-12-02 18:04:22 +01:00
<figcaption>Detail view of notification with title</figcaption>
</figure>
2021-12-02 05:08:12 +01:00
## Message priority
All messages have a priority, which defines how urgently your phone notifies you. You can set custom
2021-12-02 23:27:31 +01:00
notification sounds and vibration patterns on your phone to map to these priorities (see [Android config](subscribe/phone.md)).
2021-12-02 05:08:12 +01:00
The following priorities exist:
| Priority | Icon | ID | Name | Description |
|---|---|---|---|---|
2021-12-02 23:27:31 +01:00
| Max priority | ![min priority](static/img/priority-5.svg) | `5` | `max`/`urgent` | Really long vibration bursts, default notification sound with a pop-over notification. |
| High priority | ![min priority](static/img/priority-4.svg) | `4` | `high` | Long vibration burst, default notification sound with a pop-over notification. |
2021-12-02 05:08:12 +01:00
| **Default priority** | *(none)* | `3` | `default` | Short default vibration and sound. Default notification behavior. |
2021-12-02 23:27:31 +01:00
| Low priority | ![min priority](static/img/priority-2.svg) |`2` | `low` | No vibration or sound. Notification will not visibly show up until notification drawer is pulled down. |
| Min priority | ![min priority](static/img/priority-1.svg) | `1` | `min` | No vibration or sound. The notification will be under the fold in "Other notifications". |
2021-12-02 05:08:12 +01:00
You can set the priority with the header `X-Priority` (or any of its aliases: `Priority`, `prio`, or `p`).
=== "Command line (curl)"
```
curl -H "X-Priority: 5" -d "An urgent message" ntfy.sh/phil_alerts
curl -H "Priority: low" -d "Low priority message" ntfy.sh/phil_alerts
curl -H p:4 -d "A high priority message" ntfy.sh/phil_alerts
```
=== "HTTP"
``` http
POST /phil_alerts HTTP/1.1
Host: ntfy.sh
Priority: 5
An urgent message
```
=== "JavaScript"
``` javascript
fetch('https://ntfy.sh/phil_alerts', {
method: 'POST',
body: 'An urgent message',
headers: { 'Priority': '5' }
})
```
=== "Go"
``` go
req, _ := http.NewRequest("POST", "https://ntfy.sh/phil_alerts", strings.NewReader("An urgent message"))
req.Header.Set("Priority", "5")
http.DefaultClient.Do(req)
```
=== "PHP"
2021-12-04 02:38:21 +01:00
``` php-inline
2021-12-02 05:08:12 +01:00
file_get_contents('https://ntfy.sh/phil_alerts', false, stream_context_create([
'http' => [
'method' => 'POST',
'header' =>
"Content-Type: text/plain\r\n" .
"Priority: 5",
'content' => 'An urgent message'
]
]));
```
<figure markdown>
2021-12-02 23:27:31 +01:00
![priority notification](static/img/priority-detail-overview.png){ width=500 }
2021-12-02 05:08:12 +01:00
<figcaption>Detail view of priority notifications</figcaption>
</figure>
## Tags & emojis 🥳 🎉
2021-12-02 18:04:22 +01:00
You can tag messages with emojis and other relevant strings:
2021-12-02 05:08:12 +01:00
2021-12-02 23:27:31 +01:00
* **Emojis**: If a tag matches an [emoji short code](emojis.md), it'll be converted to an emoji and prepended
2021-12-02 18:04:22 +01:00
to title or message.
* **Other tags:** If a tag doesn't match, it will be listed below the notification.
2021-12-02 05:08:12 +01:00
2021-12-02 18:04:22 +01:00
This feature is useful for things like warnings (⚠️, ️🚨, or 🚩), but also to simply tag messages otherwise (e.g. script
2021-12-02 23:27:31 +01:00
names, hostnames, etc.). Use [the emoji short code list](emojis.md) to figure out what tags can be converted to emojis.
2021-12-02 18:04:22 +01:00
Here's an **excerpt of emojis** I've found very useful in alert messages:
2021-12-02 05:08:12 +01:00
2021-12-02 18:04:22 +01:00
<table class="remove-md-box"><tr>
<td>
<table><thead><tr><th>Tag</th><th>Emoji</th></tr></thead><tbody>
<tr><td><code>+1</code></td><td>👍️</td></tr>
<tr><td><code>partying_face</code></td><td>🥳</td></tr>
<tr><td><code>tada</code></td><td>🎉</td></tr>
<tr><td><code>heavy_check_mark</code></td><td>✔️</td></tr>
<tr><td><code>loudspeaker</code></td><td>📢</td></tr>
<tr><td>...</td><td>...</td></tr>
</tbody></table>
</td>
<td>
<table><thead><tr><th>Tag</th><th>Emoji</th></tr></thead><tbody>
<tr><td><code>-1</code></td><td>👎️</td></tr>
<tr><td><code>warning</code></td><td>⚠️</td></tr>
<tr><td><code>rotating_light</code></td><td>️🚨</td></tr>
<tr><td><code>triangular_flag_on_post</code></td><td>🚩</td></tr>
<tr><td><code>skull</code></td><td>💀</td></tr>
<tr><td>...</td><td>...</td></tr>
</tbody></table>
</td>
<td>
<table><thead><tr><th>Tag</th><th>Emoji</th></tr></thead><tbody>
<tr><td><code>facepalm</code></td><td>🤦</td></tr>
<tr><td><code>no_entry</code></td><td></td></tr>
<tr><td><code>no_entry_sign</code></td><td>🚫</td></tr>
<tr><td><code>cd</code></td><td>💿</td></tr>
<tr><td><code>computer</code></td><td>💻</td></tr>
<tr><td>...</td><td>...</td></tr>
</tbody></table>
</td>
</tr></table>
2021-12-07 21:39:42 +01:00
You can set tags with the `X-Tags` header (or any of its aliases: `Tags`, `tag`, or `ta`). Specify multiple tags by separating
2021-12-02 18:04:22 +01:00
them with a comma, e.g. `tag1,tag2,tag3`.
=== "Command line (curl)"
```
curl -H "X-Tags: warning,mailsrv13,daily-backup" -d "Backup of mailsrv13 failed" ntfy.sh/backups
curl -H "Tags: horse,unicorn" -d "Unicorns are just horses with unique horns" ntfy.sh/backups
curl -H ta:dog -d "Dogs are awesome" ntfy.sh/backups
```
=== "HTTP"
``` http
POST /backups HTTP/1.1
Host: ntfy.sh
Tags: warning,mailsrv13,daily-backup
Backup of mailsrv13 failed
```
=== "JavaScript"
``` javascript
fetch('https://ntfy.sh/backups', {
method: 'POST',
body: 'Backup of mailsrv13 failed',
headers: { 'Tags': 'warning,mailsrv13,daily-backup' }
})
```
=== "Go"
``` go
req, _ := http.NewRequest("POST", "https://ntfy.sh/backups", strings.NewReader("Backup of mailsrv13 failed"))
req.Header.Set("Tags", "warning,mailsrv13,daily-backup")
http.DefaultClient.Do(req)
```
=== "PHP"
2021-12-04 02:38:21 +01:00
``` php-inline
2021-12-02 18:04:22 +01:00
file_get_contents('https://ntfy.sh/backups', false, stream_context_create([
'http' => [
'method' => 'POST',
'header' =>
"Content-Type: text/plain\r\n" .
"Tags: warning,mailsrv13,daily-backup",
'content' => 'Backup of mailsrv13 failed'
]
]));
```
<figure markdown>
2021-12-02 23:27:31 +01:00
![priority notification](static/img/notification-with-tags.png){ width=500 }
2021-12-02 18:04:22 +01:00
<figcaption>Detail view of notifications with tags</figcaption>
</figure>
2021-12-02 05:08:12 +01:00
2021-12-11 06:06:25 +01:00
## Scheduled delivery
You can delay the delivery of messages and let ntfy send them at a later date. This can be used to send yourself
reminders or even to execute commands at a later date (if your subscriber acts on messages).
Usage is pretty straight forward. You can set the delivery time using the `X-Delay` header (or any of its aliases: `Delay`,
`X-At`, `At`, `X-In` or `In`), either by specifying a Unix timestamp (e.g. `1639194738`), a duration (e.g. `30m`,
`3h`, `2 days`), or a natural language time string (e.g. `10am`, `8:30pm`, `tomorrow, 3pm`, `Tuesday, 7am`,
[and more](https://github.com/olebedev/when)).
As of today, the minimum delay you can set is **10 seconds** and the maximum delay is **3 days**. This can currently
not be configured otherwise ([let me know](https://github.com/binwiederhier/ntfy/issues) if you'd like to change
these limits).
For the purposes of [message caching](config.md#message-cache), scheduled messages are kept in the cache until 12 hours
after they were delivered (or whatever the server-side cache duration is set to). For instance, if a message is scheduled
to be delivered in 3 days, it'll remain in the cache for 3 days and 12 hours. Also note that naturally,
[turning off server-side caching](#message-caching) is not possible in combination with this feature.
=== "Command line (curl)"
```
curl -H "At: tomorrow, 10am" -d "Good morning" ntfy.sh/hello
curl -H "In: 30min" -d "It's 30 minutes later now" ntfy.sh/reminder
curl -H "Delay: 1639194738" -d "Unix timestamps are awesome" ntfy.sh/itsaunixsystem
```
=== "HTTP"
``` http
POST /hello HTTP/1.1
Host: ntfy.sh
At: tomorrow, 10am
Good morning
```
=== "JavaScript"
``` javascript
fetch('https://ntfy.sh/hello', {
method: 'POST',
body: 'Good morning',
headers: { 'At': 'tomorrow, 10am' }
})
```
=== "Go"
``` go
req, _ := http.NewRequest("POST", "https://ntfy.sh/hello", strings.NewReader("Good morning"))
req.Header.Set("At", "tomorrow, 10am")
http.DefaultClient.Do(req)
```
=== "PHP"
``` php-inline
file_get_contents('https://ntfy.sh/backups', false, stream_context_create([
'http' => [
'method' => 'POST',
'header' =>
"Content-Type: text/plain\r\n" .
"At: tomorrow, 10am",
'content' => 'Good morning'
]
]));
```
Here are a few examples (assuming today's date is **12/10/2021, 9am, Eastern Time Zone**):
<table class="remove-md-box"><tr>
<td>
<table><thead><tr><th><code>Delay/At/In</code> header</th><th>Message will be delivered at</th><th>Explanation</th></tr></thead><tbody>
<tr><td><code>30m</code></td><td>12/10/2021, 9:<b>30</b>am</td><td>30 minutes from now</td></tr>
<tr><td><code>2 hours</code></td><td>12/10/2021, <b>11:30</b>am</td><td>2 hours from now</td></tr>
<tr><td><code>1 day</code></td><td>12/<b>11</b>/2021, 9am</td><td>24 hours from now</td></tr>
<tr><td><code>10am</code></td><td>12/10/2021, <b>10am</b></td><td>Today at 10am (same day, because it's only 9am)</td></tr>
<tr><td><code>8am</code></td><td>12/<b>11</b>/2021, <b>8am</b></td><td>Tomorrow at 8am (because it's 9am already)</td></tr>
<tr><td><code>1639152000</code></td><td>12/10/2021, 11am (EST)</td><td> Today at 11am (EST)</td></tr>
</tbody></table>
</td>
</tr></table>
2021-12-09 18:15:17 +01:00
## Advanced features
### Message caching
!!! info
If `Cache: no` is used, messages will only be delivered to connected subscribers, and won't be re-delivered if a
client re-connects. If a subscriber has (temporary) network issues or is reconnecting momentarily,
**messages might be missed**.
2021-12-09 16:23:17 +01:00
By default, the ntfy server caches messages on disk for 12 hours (see [message caching](config.md#message-cache)), so
all messages you publish are stored server-side for a little while. The reason for this is to overcome temporary
client-side network disruptions, but arguably this feature also may raise privacy concerns.
To avoid messages being cached server-side entirely, you can set `X-Cache` header (or its alias: `Cache`) to `no`.
This will make sure that your message is not cached on the server, even if server-side caching is enabled. Messages
are still delivered to connected subscribers, but [`since=`](subscribe/api.md#fetching-cached-messages) and
2021-12-11 06:06:25 +01:00
[`poll=1`](subscribe/api.md#polling-for-messages) won't return the message anymore.
2021-12-09 16:23:17 +01:00
=== "Command line (curl)"
```
curl -H "X-Cache: no" -d "This message won't be stored server-side" ntfy.sh/mytopic
curl -H "Cache: no" -d "This message won't be stored server-side" ntfy.sh/mytopic
```
=== "HTTP"
``` http
POST /mytopic HTTP/1.1
Host: ntfy.sh
Cache: no
This message won't be stored server-side
```
=== "JavaScript"
``` javascript
fetch('https://ntfy.sh/mytopic', {
method: 'POST',
body: 'This message won't be stored server-side',
headers: { 'Cache': 'no' }
})
```
=== "Go"
``` go
req, _ := http.NewRequest("POST", "https://ntfy.sh/mytopic", strings.NewReader("This message won't be stored server-side"))
req.Header.Set("Cache", "no")
http.DefaultClient.Do(req)
```
=== "PHP"
``` php-inline
file_get_contents('https://ntfy.sh/mytopic', false, stream_context_create([
'http' => [
'method' => 'POST',
'header' =>
"Content-Type: text/plain\r\n" .
"Cache: no",
'content' => 'This message won't be stored server-side'
]
]));
```
2021-12-09 18:15:17 +01:00
2021-12-11 06:06:25 +01:00
### Disable Firebase
2021-12-09 18:15:17 +01:00
!!! info
If `Firebase: no` is used and [instant delivery](subscribe/phone.md#instant-delivery) isn't enabled in the Android
app (Google Play variant only), **message delivery will be significantly delayed (up to 15 minutes)**. To overcome
this delay, simply enable instant delivery.
The ntfy server can be configured to use [Firebase Cloud Messaging (FCM)](https://firebase.google.com/docs/cloud-messaging)
(see [Firebase config](config.md#firebase-fcm)) for message delivery on Android (to minimize the app's battery footprint).
The ntfy.sh server is configured this way, meaning that all messages published to ntfy.sh are also published to corresponding
FCM topics.
If you'd like to avoid forwarding messages to Firebase, you can set the `X-Firebase` header (or its alias: `Firebase`)
to `no`. This will instruct the server not to forward messages to Firebase.
=== "Command line (curl)"
```
curl -H "X-Firebase: no" -d "This message won't be forwarded to FCM" ntfy.sh/mytopic
curl -H "Firebase: no" -d "This message won't be forwarded to FCM" ntfy.sh/mytopic
```
=== "HTTP"
``` http
POST /mytopic HTTP/1.1
Host: ntfy.sh
Firebase: no
This message won't be forwarded to FCM
```
=== "JavaScript"
``` javascript
fetch('https://ntfy.sh/mytopic', {
method: 'POST',
body: 'This message won't be forwarded to FCM',
headers: { 'Firebase': 'no' }
})
```
=== "Go"
``` go
req, _ := http.NewRequest("POST", "https://ntfy.sh/mytopic", strings.NewReader("This message won't be forwarded to FCM"))
req.Header.Set("Firebase", "no")
http.DefaultClient.Do(req)
```
=== "PHP"
``` php-inline
file_get_contents('https://ntfy.sh/mytopic', false, stream_context_create([
'http' => [
'method' => 'POST',
'header' =>
"Content-Type: text/plain\r\n" .
"Firebase: no",
'content' => 'This message won't be stored server-side'
]
]));
```