Skip to main content

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 and IMAP credentials:

# Gmail - same app password for SMTP and IMAP
machine smtp.gmail.com login you@gmail.com password your-app-password
machine imap.gmail.com login you@gmail.com password your-app-password

# Migadu
machine smtp.migadu.com login you@migadu.com password your-password
machine imap.migadu.com login you@migadu.com password your-password

The IMAP credentials allow sent emails to appear in your mail client's sent folder.

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 followed by the email body:

---
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>
attachments:
  - ./report.pdf
  - ~/documents/data.xlsx
---

Body content goes here.

Required Fields

  • from - Sender email address (supports display names: "John Doe john@example.com")
  • to - Recipient(s), can be string or list
  • subject - Email subject

Optional Fields

  • cc - Carbon copy recipient(s)
  • bcc - Blind carbon copy recipient(s)
  • date - ISO 8601 or RFC 2822 format
  • message-id - Unique message identifier
  • in-reply-to - Message-ID being replied to
  • references - List of message-IDs for threading
  • reply-to - Reply-to address
  • attachments - Files to attach (see below)

Multiple Recipients

---
to:
  - alice@example.com
  - bob@example.com
cc: team@example.com
---

Attachments

Attach files to emails by listing their paths. Paths support:

  • Relative paths: ./report.pdf
  • Home directory: ~/documents/data.xlsx
  • Absolute paths: /abs/path/file.pdf

Single attachment (scalar):

attachments: ./report.pdf

Multiple attachments (list):

attachments:
  - ./report.pdf
  - ~/documents/data.xlsx
  - /tmp/image.png

Validation rules:

  • Files must exist (error if not found)
  • Cannot attach directories (error if path is directory)
  • Empty files are rejected (0 bytes = error)
  • Large files (>10MB) trigger warnings
  • MIME type is auto-detected

Display Names

The from field and recipient fields support RFC 5322 display names:

from: John Doe <john@example.com>
to: Alice Smith <alice@example.com>
cc: "Bob Johnson (Manager)" <bob@example.com>

Display names are preserved through save/load cycles.

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

Sent Folder Upload (IMAP)

After successfully sending an email via SMTP, mdmailbox automatically uploads a copy to your IMAP "Sent" folder so sent emails appear in your mail client.

Setup: Add IMAP credentials to .authinfo alongside SMTP credentials:

# Gmail example
machine smtp.gmail.com login you@gmail.com password your-app-password
machine imap.gmail.com login you@gmail.com password your-app-password

# Migadu example
machine smtp.migadu.com login you@migadu.com password your-password
machine imap.migadu.com login you@migadu.com password your-password

How it works:

  1. Email is sent via SMTP (e.g., smtp.gmail.com)
  2. mdmailbox converts the SMTP hostname to IMAP (e.g., imap.gmail.com)
  3. Looks up IMAP credentials in .authinfo
  4. Uploads a copy to the "Sent" folder via IMAP APPEND
  5. If IMAP credentials not found, logs a warning but send still succeeds

Note: Gmail and most email providers use the same app password for both SMTP and IMAP.

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}")

Emacs Integration

An Emacs major mode (mdmailbox-mode) is included for composing and sending emails directly from Emacs.

Quick Setup

DOOM Emacs:

# Copy emacs/ to DOOM modules
mkdir -p ~/.config/doom/modules/lang/mdmailbox
cp emacs/* ~/.config/doom/modules/lang/mdmailbox/

Add to ~/.config/doom/init.el:

:lang
(mdmailbox)

Then: doom sync

Other Emacs:

(add-to-list 'load-path "~/.emacs.d/lisp/mdmailbox")
(require 'mdmailbox)

Usage

  1. Open a draft: ~/Mdmailbox/drafts/hello.md
  2. mdmailbox-mode loads automatically
  3. Preview: C-c C-p - validate with mdmailbox send --dry-run
  4. Send: C-c C-c - send with confirmation
  5. Abort: C-c C-k - discard draft

See emacs/README.md for full documentation and installation options.

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

Metadata

Release files for mdmailbox 0.1.13

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for mdmailbox 0.1.13
File Size Uploaded
mdmailbox-0.1.13.tar.gz 63.3 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for mdmailbox 0.1.13
File Interpreter ABI Platform
mdmailbox-0.1.13-py3-none-any.whl Python 3 none any Details

Total release size: 90.8 kB

Release files / mdmailbox-0.1.13.tar.gz

Download URL mdmailbox-0.1.13.tar.gz
Size 63.3 kB
Tags Source
SHA-256 checksum
How to use checksums
f183dab68bdd46a77104788d732410c2bc0a7b38ddeda4444afbc84bb28904f6
BLAKE2b-256 checksum
How to use checksums
46b3ffd5ba1a0e9b24c0a6abc58c9a1a0aaa70ede393a84c9286f8874e4e2bec
Upload date
Uploaded using Trusted Publishing?
What is 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":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

Release files / mdmailbox-0.1.13-py3-none-any.whl

Download URL mdmailbox-0.1.13-py3-none-any.whl
Size 27.5 kB
Tags Python 3
SHA-256 checksum
How to use checksums
0ce06b71a2a87d3e4371c6a9cc7a8f69d7fec382e5b00fd9f0f1382dc32f2750
BLAKE2b-256 checksum
How to use checksums
94ba6332552522ec33da1108a88d755d2898c8130aee039172e78c9dbe9e6e25
Upload date
Uploaded using Trusted Publishing?
What is 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":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

Release history Release notifications | RSS feed

This release

0.1.13 This release

2 release files

0.1.11

2 release files

0.1.10

2 release files

0.1.8

2 release files

0.1.7

2 release files

0.1.6

2 release files

0.1.5

2 release files

0.1.4

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page