A one-way firehose: logs into Mattermost as a regular user and forwards every event that account can see (public channels, private channels, direct messages, group DMs) to a single Telegram chat. No reply path, no gateway, no routing config. Read-only observer.
Written because matterbridge does not bridge DMs and group-DMs — it only bridges explicitly configured channels, which can't include per-user direct channels.
Extracted from https://github.com/styliteag/matterbridge branch
private-messages. That branch contains WebSocket stability fixes in
vendor/github.com/matterbridge/matterclient/:
- atomic reconnect flag (prevents double-reconnect races)
- handler supervisor (restarts
handleMatterClientif it panics) - stale-pong watchdog (detects dead but not-yet-closed WS)
- drop-oldest buffer behavior (instead of blocking when MessageChan full)
- ALIVE counters and MM-SEND-GW logging
Important: this repo currently uses the released matterclient
(v0.0.0-20240817214420-3d4c3aef3dc1), which does NOT have those
fixes. Options to resolve:
- Fork
github.com/matterbridge/matterclienttogithub.com/styliteag/matterclient, commit the fixes from theprivate-messagesvendor tree, and add areplacedirective ingo.mod. - Vendor matterclient into this repo and apply the patches locally
under
vendor/.
Option 1 is cleaner. Neither has been done yet.
- Read config from env (
MM_*,TG_TOKEN,TG_CHAT_ID). matterclient.New(...)thenLogin()— opens the websocket.- Range over
mc.MessageChan— matterclient delivers every event the logged-in user can see, including DMs/GDMs. - For each message: look up channel type via
mc.Client.GetChannel(ctx, id, "")to label as PUB/PRIV/DM/GDM. - Format as
[TYPE team/channel] <user> text, split at 3900 chars, send to Telegram withDisableNotification=true. - If
MessageChanever closes,log.Fatalso the container restarts.
github.com/matterbridge/matterclient— Mattermost WS clientgithub.com/mattermost/mattermost/server/publicv0.1.6 — model types, noteGetChannelsignature is(ctx, id, etag)github.com/go-telegram-bot-api/telegram-bot-api/v5v5.5.1
GitHub Actions builds a multi-arch (amd64, arm64) image on every push
to master/main and on tag v*, publishing to
ghcr.io/styliteag/mattermost2telegrambot. Run via docker-compose.yml
with a .env file (see .env.example).
- Commits:
<type>: <description>(feat, fix, refactor, docs, test, chore, perf, ci) - No co-authored-by attribution
- Go:
gofmt,go vet. Accept interfaces, return structs. Usecontext.Contextfor timeouts. Wrap errors with%w. - Functions under 50 lines. No console noise — use
logpackage.
- Must be a member of every channel/DM you want forwarded.
- Use a dedicated human-style user account (not a bot account) because bot accounts can't receive DMs from humans unless System Console → Bot Accounts has "Enable Bot Account Creation" + DM permissions configured. A regular user account is simpler.
- A personal access token is preferred over a password in
MM_PASS.
- Port matterclient WS fixes (see Origin section) — highest value.
- Add a small allow/deny filter (e.g. skip system messages, skip channels matching a pattern).
- Markdown/HTML formatting for Telegram (currently plain text).
- Attachment handling (currently ignored; only
m.Textis forwarded). - Prometheus metrics endpoint.
- Add a reply path back to Mattermost. This is intentionally read-only.
- Pull in matterbridge's gateway/config/bridge machinery. The whole point of this repo is avoiding that complexity.
- Add retry/reconnect logic around
mc.MessageChanin main — that's matterclient's job. If it's broken, fix matterclient.