Starstreak/MailSalonSync - Cerberus Games Git: Welcome to Cerberus Gaming - Fuck you, I'm coding
This website requires JavaScript.
Starstreak/MailSalonSync
Watch
Star
Fork
You've already forked MailSalonSync
Code
Issues
Pull requests
Projects
Releases
Packages
Wiki
Activity
Actions
No description
4 commits
1 branch
0 tags
75 KiB
Go
99.7%
Makefile
0.3%
main
Find a file
HTTPS
Download ZIP<br>Download TAR.GZ<br>Download BUNDLE
Open with VS Code
Open with VSCodium
Open with Intellij IDEA
Exact
Exact
Union
RegExp
Starstreak
7c782760bf
Fix imports
2026-08-20 03:51:32 +00:00
cmd/MailSalonSync
Fix imports
2026-08-20 03:51:32 +00:00
internal
Fix imports
2026-08-20 03:51:32 +00:00
config.example.json
New program
2026-08-19 08:40:06 -04:00
go.mod
New program
2026-08-19 08:40:06 -04:00
LICENSE
New program
2026-08-19 08:40:06 -04:00
logo.avif
New artwork
2026-08-19 08:43:54 -04:00
mailsalon.svg
New artwork
2026-08-19 08:43:54 -04:00
Makefile
New program
2026-08-19 08:40:06 -04:00
README.md
Update README.md
2026-08-19 12:44:49 +00:00
README.md
MailSalonSync
MailSalonSync is a small, Maildir-first replacement for the common OfflineIMAP workflow, written in Go. It can mirror configured folders from either IMAP or JMAP accounts, propagate deletions in both directions, handle multiple accounts and mailbox-to-directory mappings, and submit raw RFC 5322 messages with JMAP.
While it works, an interactive terminal gets a Charm Bubble Tea/Bubbles spinner with the current account, mailbox, operation, and running add/delete counts. When stdout is redirected, it falls back to normal line-oriented status output.
Features
Multiple accounts in one config file.
IMAP and JMAP accounts can be mixed.
Any number of remote mailbox -> local Maildir mappings per account.
Remote messages are stored as normal Maildir files (new/, cur/, tmp/).
Stable per-message state survives Maildir moves from new/ to cur/ and normal Maildir flag suffix changes.
Remote deletion removes the corresponding local Maildir file.
With propagate_deletes: true, deleting the local Maildir file propagates back to the server.
IMAP deletion uses UIDPLUS UID EXPUNGE when available. A broad EXPUNGE is refused by default on servers without UIDPLUS.
JMAP deletion removes the message from the mapped mailbox; if that is its final mailbox, the Email is destroyed.
JMAP send accepts a complete RFC 5322 message from a file or stdin.
Secrets can come from environment variables or commands such as pass, so they do not need to live in the config file.
IMAP supports implicit TLS, STARTTLS, and explicit plaintext mode.
JMAP session/API/upload/download endpoints are required to use HTTPS.
Ctrl-C or q in the interactive status UI cancels the underlying sync/send operation.
Build
The project targets Go 1.23 and uses the Go-1.23-compatible Charm v1 packages.
go mod tidy<br>go build -o MailSalonSync ./cmd/MailSalonSync<br>The only non-standard-library dependencies are Charm Bubble Tea and Bubbles.
Commands
Sync every configured account:
MailSalonSync -config ~/.config/MailSalonSync/config.json sync<br>Sync one account, or a comma-separated subset:
MailSalonSync -config ~/.config/MailSalonSync/config.json sync -account personal-imap<br>MailSalonSync -config ~/.config/MailSalonSync/config.json sync -account personal-imap,work-jmap<br>Validate the configuration:
MailSalonSync -config ~/.config/MailSalonSync/config.json check-config<br>Print an example configuration:
MailSalonSync example-config<br>Send a raw message via JMAP:
MailSalonSync -config ~/.config/MailSalonSync/config.json \<br>jmap-send -account work-jmap -file message.eml<br>Or make it act like a simple sendmail-style sink:
cat message.eml | MailSalonSync -config ~/.config/MailSalonSync/config.json \<br>jmap-send -account work-jmap<br>Configuration
The default config path is $XDG_CONFIG_HOME/MailSalonSync/config.json, falling back to ~/.config/MailSalonSync/config.json.
See config.example.json for a complete two-account example.
A mailbox mapping has two fields:
{ "remote": "INBOX", "local": "INBOX" }<br>local is relative to the account's local_root, unless it is an absolute path. Use "." to use local_root itself as the Maildir.
For JMAP, a remote mailbox can be selected three ways:
{ "remote": "role:inbox", "local": "INBOX" }<br>{ "remote": "Archive/Projects", "local": "Projects" }<br>{ "remote": "id:server-mailbox-id", "local": "Special" }<br>role: is usually the most robust choice for Inbox, Sent, Drafts, Trash, and similar special-use mailboxes because it does not depend on a localized display name.
IMAP account
"name": "personal-imap",<br>"protocol": "imap",<br>"local_root": "~/Mail/personal",<br>"propagate_deletes": true,<br>"mailboxes": [<br>{ "remote": "INBOX", "local": "INBOX" },<br>{ "remote": "Archive", "local": "Archive" }<br>],<br>"imap": {<br>"address": "imap.example.com:993",<br>"username": "me@example.com",<br>"password_env": "PERSONAL_IMAP_PASSWORD",<br>"security": "tls"<br>security may be tls,...