Guide
Send Email to Mattermost (CLI)
Mattermost is the self-hosted chat platform many engineering and ops teams run instead of Slack, and routing key email into a channel keeps everyone in one place. The bridge is an incoming webhook plus three commands. The CLI hands you the message as JSON, jq shapes the payload, and curl posts it. This guide builds an email-to-Mattermost pipeline you fully control, formats sender and subject into the channel message, and runs it on a schedule with no connector subscription.
Written by Prem Keshari Senior SRE
Reviewed by Qasim Muhammad
Command references used in this guide: nylas email search, nylas email list, and nylas email read.
Why post email to a Mattermost channel?
Posting email to Mattermost puts inbound mail where your team already works, so support requests, deploy alerts, or billing notices land in a channel instead of one person's inbox. Mattermost is open-source and self-hosted, which is why many teams under data-residency rules run it instead of Slack. An incoming webhook turns any email into a channel message in one HTTP call.
The pattern is three pieces: the Nylas CLI reads the mailbox and returns JSON, jq builds the payload, and curl posts it. There is no paid connector and no per-message fee. Mattermost incoming webhooks accept a JSON body with a text field that renders as Markdown, documented in the Mattermost incoming webhooks reference. A single mailbox grant on the CLI side feeds every channel you want, and the webhook URL is the only secret you store. Setup runs in under 5 minutes once the webhook exists.
How do I create a Mattermost incoming webhook?
Create a Mattermost incoming webhook in the System Console or channel integrations menu under Integrations then Incoming Webhooks, pick the target channel, and copy the generated URL. The URL ends in a 26-character token and looks like https://your-mattermost.example.com/hooks/xxxxxxxx. Treat it as a secret because anyone holding it can post to that channel.
Test the webhook before wiring email into it. A bare POST with a text field confirms the URL works and that the server allows webhook posts, a setting an admin can disable globally. The endpoint returns the literal body ok with HTTP 200 on success; a 403 means webhooks are disabled in the System Console. Store the URL in an environment variable so it never lands in shell history or a committed script.
# Store the webhook URL once, then test it
export MM_WEBHOOK="https://your-mattermost.example.com/hooks/xxxxxxxx"
curl -s -X POST "$MM_WEBHOOK" \
-H "Content-Type: application/json" \
-d '{"text":"Mattermost webhook is live."}'How do I pull the right emails as JSON?
Pull the emails as JSON with nylas email search, narrowing to exactly the mail you want in the channel. The --from, --unread, and --after flags filter server-side, so you never download the whole inbox. The --json flag returns a parseable array instead of a table.
Scope matters because the average professional receives 121 emails per day, per the Radicati Group, and posting all of them would bury the channel. Filter to a sender, a folder, or a date window so only signal reaches Mattermost. The command below pulls unread messages from a support alias received on or after a date and writes them to a file the next step reads. The CLI auto-paginates past 200 results when you raise --limit, so a wide window stays in one call.
# Pull unread support mail since a date, as JSON
nylas email search "*" \
--from "support@yourcompany.com" \
--unread \
--after 2026-06-01 \
--json --limit 50 > inbox.jsonHow do I build the Mattermost payload with jq?
Build the payload with jq, mapping each message's subject, sender, and snippet into a single text string that Mattermost renders as Markdown. The webhook accepts one message per POST, so loop over the array and post each message separately. Bold the subject with ** and prefix the sender so the channel reads cleanly.
Use jq -c to emit one compact JSON object per line, then have jq construct the webhook body so quoting and escaping are handled for you instead of hand-built in the shell. A subject containing a quote or backslash would break a string you assembled manually; passing the values through jq escapes them per the JSON spec in RFC 8259. The loop below posts each message and prints the webhook's ok response so you can confirm delivery.
# One POST per message; jq builds and escapes the body
jq -c '.[]' inbox.json | while read -r msg; do
body=$(echo "$msg" | jq -c '{
text: ("**" + (.subject // "(no subject)") + "**\n"
+ "From: " + (.from[0].email // "unknown") + "\n"
+ (.snippet // ""))
}')
curl -s -X POST "$MM_WEBHOOK" \
-H "Content-Type: application/json" \
-d "$body"
doneHow do I run it on a schedule without flooding the channel?
Run the pipeline from cron and scope each run to a short window so the channel never floods. A search filtered to --unread with a 5-minute cron interval posts only mail that arrived since the last run, and marking messages read after posting prevents duplicates on the next pass. Twelve runs an hour keeps Mattermost current without re-posting old threads.
De-duplicate on a stable field. The CLI returns each message's ID, so after a successful post you can mark it read with nylas email mark, dropping it from the next --unread query. For near-real-time delivery, drive the same payload step from a message.created webhook instead of a poll; the formatting code is identical and only the trigger changes. A cron entry runs the script every 5 minutes and logs failures for review.
# crontab -e — run every 5 minutes, log output
*/5 * * * * /usr/local/bin/email-to-mattermost.sh >> /var/log/mm-email.log 2>&1Next steps
- Email to Slack notifications — the same pattern into a Slack channel
- Email to Discord notifications — Discord webhooks instead of Mattermost
- Email to Telegram notifications — push email to a Telegram chat
- Extract email data with jq — the JSON-shaping toolkit behind the payload
- Parse inbound email webhooks — post messages the moment they arrive
- Full command reference — every flag and subcommand documented
Provider behavior is described from documented behavior, not from a verified end-to-end test on each backend. References: Mattermost Markdown formatting, Gmail API search filtering, and Microsoft Graph list messages.