discord-hook
An async Rust crate for sending rich messages to Discord via webhooks.
Features
- Typed message builder — construct
WebhookMessageandEmbedpayloads with a fluent builder API; validation happens at.build()time, not at runtime. discord_message!/embed!macros — shorthand for common one-liner messages.- Rate-limit awareness — Discord's HTTP 429 surfaces as
WebhookError::RateLimitedwith aretry_after_msfield so you can back off correctly. - Thread support — post into existing threads or create new ones in forum channels.
AllowedMentionscontrol — always safe to pass user-generated content; silence@everyonepings with a single call.- JSON code blocks — format any
Serializevalue as a Discord code block in message content or embed descriptions/fields. - Pluggable TLS —
rustlsby default (pure Rust, no OpenSSL); opt intonative-tlsvia a feature flag. WebhookSendertrait — write code that is generic over notification backends (Discord, Slack, etc.) viahooksmith-core.
Installation
[]
= "0.1"
= { = "1", = ["full"] }
TLS backends
| Feature | Default | Notes |
|---|---|---|
rustls |
✅ | Pure Rust — no system OpenSSL required |
native-tls |
❌ | Uses the OS TLS stack (OpenSSL / SChannel / Secure Transport) |
To switch to native-tls:
= { = "0.1", = false, = ["native-tls"] }
Quick start
use ;
async
Macros
For simple messages the discord_message! and embed! macros remove boilerplate:
use ;
#
# async
Sending to a thread
# use ;
#
# async
Safe handling of user-generated content
Always suppress auto-parsed mentions when the message body contains input you do not fully control:
# use ;
#
# async
JSON payloads in embeds
Any serde::Serialize value can be rendered as a pretty code block:
use Embed;
use Serialize;
let embed = builder
.title
.json_description
.expect
.build;
Rate limits
Discord can return HTTP 429. The client surfaces this as:
RateLimited
Back off and retry after that many milliseconds. For automatic retry with
exponential backoff use HttpClient::post_json_with_retry from hooksmith-core.
Error handling
| Variant | When |
|---|---|
WebhookError::InvalidUrl |
URL is not HTTPS or doesn't target discord.com/api/webhooks/ |
WebhookError::EmptyMessage |
.build() called with no content and no embeds |
WebhookError::Http |
Transport-level reqwest failure |
WebhookError::RateLimited |
Discord returned HTTP 429 |
WebhookError::ApiError |
Any other non-2xx response from Discord |
WebhookError::Json |
JSON serialization failed |
Writing backend-agnostic code
discord-hook re-exports WebhookSender from hooksmith-core. Implement it
once and swap backends without changing call sites:
use WebhookSender;
async
License
MIT — see LICENSE.