Email as plain text files with YAML frontmatter
Project description
mdmailbox
Email as plain text files with YAML headers.
What is this?
mdmail treats email as simple text files:
---
from: me@example.com
to: alice@example.com
subject: Quick question
---
Hey Alice,
Are we still on for tomorrow?
Best,
Me
Save this as ~/Mdmailbox/drafts/meeting.md, run mdmailbox send ~/Mdmailbox/drafts/meeting.md, and it's sent.
Why?
- Plain text - Edit emails in your favorite editor
- Git-friendly - Track your email history with version control
- Scriptable - Automate email with simple shell scripts or Python
- LLM-friendly - Easy for AI tools to read, search, and compose emails
- No lock-in - It's just files. Move them, grep them, back them up
Installation
pip install mdmailbox
Or with uv:
uv tool install mdmailbox
Quick Start
1. Configure credentials
Create ~/.authinfo with your SMTP credentials:
machine smtp.gmail.com login you@gmail.com password your-app-password
machine smtp.migadu.com login you@migadu.com password your-password
2. Create a draft
mdmailbox new --to friend@example.com --subject "Hello" --from you@gmail.com
This creates ~/Mdmailbox/drafts/hello.md.
3. Edit and send
Edit the draft in your favorite editor, then:
mdmailbox send ~/Mdmailbox/drafts/hello.md
The email is sent and moved to ~/Mdmailbox/sent/.
Commands
| Command | Description |
|---|---|
mdmailbox send <file> |
Send an email |
mdmailbox send --dry-run <file> |
Validate without sending |
mdmailbox import |
Import emails from Maildir |
mdmailbox new |
Create a new email draft |
mdmailbox credentials |
Show configured SMTP credentials |
Send
# Send an email
mdmailbox send ~/Mdmailbox/drafts/hello.md
# Dry run (validate without sending)
mdmailbox send --dry-run ~/Mdmailbox/drafts/hello.md
# Use custom authinfo file
mdmailbox send --authinfo ~/secrets/.authinfo ~/Mdmailbox/drafts/hello.md
Import from Maildir
If you use mbsync or similar tools to sync email locally:
# Import all emails from ~/mail (default)
mdmailbox import
# Import from custom location
mdmailbox import --maildir ~/Maildir
# Import to custom output directory
mdmailbox import -o ~/Mdmailbox/inbox
# Limit number of emails
mdmailbox import -n 100
New Draft
# Create empty draft
mdmailbox new
# Create with fields pre-filled
mdmailbox new --to alice@example.com --subject "Meeting" --from me@gmail.com
# Specify output path
mdmailbox new -o ~/Mdmailbox/drafts/custom-name.md
Credentials
# List all configured credentials
mdmailbox credentials
# Look up credentials for specific email
mdmailbox credentials --email you@gmail.com
File Format
Every email is a text file with YAML frontmatter:
---
from: sender@example.com
to: recipient@example.com
subject: Subject line
cc: optional@example.com
date: 2025-12-08T15:30:00+01:00
message-id: <abc123@mail.example.com>
---
Body content goes here.
Multiple recipients
---
to:
- alice@example.com
- bob@example.com
cc: team@example.com
---
Directory Structure
~/Mdmailbox/
├── inbox/ # imported emails
├── drafts/ # work in progress
└── sent/ # successfully sent
Configuration
Credentials via .authinfo
mdmail uses the standard .authinfo format:
# ~/.authinfo
machine smtp.gmail.com login you@gmail.com password your-app-password
machine smtp.migadu.com login you@migadu.com password your-password
# Wildcard domain support (for aliases)
machine smtp.migadu.com login *@yourdomain.com password shared-password
When sending, mdmail looks up credentials by matching the from: address.
Features:
- Exact match
- Gmail normalization (dots and +suffix ignored for gmail.com)
- Wildcard domain matching (*@domain.com)
Set a custom path via environment variable:
export AUTHINFO_FILE=~/secrets/.authinfo
Python API
from mdmailbox import Email
from mdmailbox.smtp import send_email
from pathlib import Path
# Read an email
email = Email.from_file(Path("inbox/message.md"))
print(email.subject)
print(email.body)
# Create and save
email = Email(
from_addr="me@example.com",
to=["you@example.com"],
subject="Hello",
body="Hi there!"
)
email.save(Path("drafts/hello.md"))
# Send
result = send_email(email)
if result.success:
print(f"Sent! Message-ID: {result.message_id}")
Development
# Run tests
make test
# Install locally
make local-install
Future Ideas
See docs/adr/001-design.md for the full design document including planned features like IMAP fetch, attachments, and more.
License
MIT
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file mdmailbox-0.1.6.tar.gz.
File metadata
- Download URL: mdmailbox-0.1.6.tar.gz
- Upload date:
- Size: 35.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.9.15 {"installer":{"name":"uv","version":"0.9.15","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"NixOS","version":"24.11","id":"vicuna","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
a3540db21261802fc7c651859154f8caa5f6f51fbf4b62734a5a19cf956d7661
|
|
| MD5 |
390a66cf4d4a7e4f9048f976f1b4e82b
|
|
| BLAKE2b-256 |
ce844eb8ff435fd976898bdb68fb22e05e9f0a4affd0bd91ddff846177adb0fb
|
File details
Details for the file mdmailbox-0.1.6-py3-none-any.whl.
File metadata
- Download URL: mdmailbox-0.1.6-py3-none-any.whl
- Upload date:
- Size: 12.8 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.9.15 {"installer":{"name":"uv","version":"0.9.15","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"NixOS","version":"24.11","id":"vicuna","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
db5b257ae4a1098875e8e3e2450e7cedd6f9a9e81e5d81ea7bbb8e37b11af40e
|
|
| MD5 |
f0d059c8c357936609dd51452bd48f91
|
|
| BLAKE2b-256 |
49b171282b541f2f5cfef5558a5bd38ee8488c3a102ae4716399bc87b84d94cb
|