Skip to main content

Email-ingest automation for Codex tasks

Project description

Codemail

Automate Codex CLI tasks straight from your inbox and reply with polished HTML reports.

shell python license PRs welcome


Quick Navigation

Why Codemail

Codemail turns an email inbox into a Codex automation trigger. Any message you send to the configured address is parsed, mapped to the right Codex session, executed, and answered with a single HTML recap (complete with headings, bullet lists, and Reply-To pointing back at the task pipeline). No more juggling CLI windows when you just want to fire off a quick instruction from your phone.

Highlights:

  • Drop-in Postfix hook – point an alias or .forward at the runner and you are live.
  • Markdown-driven reports – agent output is converted to a dark, shareable status card.
  • Session smart – references and message IDs keep threads tied to Codex sessions.
  • Operator friendly – logs, state, and transcripts stay in the same places you already use.

Requirements

  • Python 3.10+
  • Codex CLI available on PATH (codex exec)
  • Postfix (or another MTA) capable of piping mail to shell commands
  • Access to the inbox you want Codemail to reply from (IMAP/SMTP credentials)

Install & First Run

  1. Clone & install
    cd ~/tools
    git clone https://github.com/BranchManager69/codemail.git
    cd codemail
    python3 -m venv .venv
    source .venv/bin/activate
    pip install -e .
    
  2. Copy the environment template
    cp .env.example .env
    # edit .env with your SMTP user, password, and desired paths
    
  3. Create the wrapper used by Postfix
    cat > bin/codemail-wrapper <<'EOF_WRAPPER'
    #!/bin/bash
    set -a
    source /home/branchmanager/tools/codemail/.env
    set +a
    exec /home/branchmanager/tools/codemail/.venv/bin/codemail-runner
    EOF_WRAPPER
    chmod +x bin/codemail-wrapper
    
  4. Point your trigger address at the wrapper
    • .forward+tasks
      |/home/branchmanager/tools/codemail/bin/codemail-wrapper
      
    • or /etc/aliases
      tasks: "|/home/branchmanager/tools/codemail/bin/codemail-wrapper"
      
      After editing aliases run newaliases.
  5. Send a smoke test Email tasks@branch.bet (or your alias) with a short request. You should receive a single HTML reply summarising the work, and ~/.codex/task-mail-runner.log will show the START/SUMMARY entries.

How It Works

email → Postfix alias/.forward → codemail-wrapper → codemail-runner → Codex CLI
                                               ↓
                                      HTML summary email
  • runner.py handles parsing, prompt construction, Codex invocation, and reply delivery.
  • state.py keeps a JSON map of message-id → session across runs.
  • markdown_render.py turns Markdown summaries into the dark status card.
  • config.py centralises env lookups so you can override paths or credentials.

Email Flow

  1. Incoming mail hits Postfix and is piped into codemail-wrapper.
  2. The wrapper exports your .env, then executes codemail-runner.
  3. The runner parses the message, finds any previous session, and shells out to codex exec in JSON streaming mode.
  4. Codex emits Markdown summary text; Codemail renders it to HTML, sets Reply-To to the task address, and emails the sender.
  5. Logs and state are appended so the next message in the thread resumes the same session.

Configuration Cheat Sheet

Variable Default Purpose
CODEMAIL_MAIL_USER codex@branch.bet From/BCC address for replies
CODEMAIL_MAIL_PASS (required) SMTP password (or app password)
CODEMAIL_PASSWORD_FILE ~/.codex_mail_pass Optional file-based password fallback
CODEMAIL_SMTP_HOST mail.branch.bet SMTP host
CODEMAIL_SMTP_PORT 587 SMTP port
CODEMAIL_STATE_PATH ~/.codex/task_mail_map.json Session mapping file
CODEMAIL_LOG_PATH ~/.codex/task-mail-runner.log Runner log
CODEMAIL_SESSION_ROOT ~/.codex/sessions Codex transcript directory
CODEMAIL_REPLY_TO tasks@branch.bet Reply-To header used on summaries
CODEMAIL_FALLBACK_RECIPIENT branch@branch.bet Where to send reports if no recipient headers are found
CODEMAIL_CODEX_BIN codex Override Codex CLI binary name/path
CODEMAIL_ALLOWED_SENDERS (unset) Comma-separated list of email addresses allowed to trigger tasks; when set, Codemail rejects other senders and emails them a notice

All variables can be set in the .env file or exported before the wrapper executes.

Mail Security Hardening

Codemail assumes you already run a responsible MTA. To keep task traffic from being spoofed (or flagged as spam) you should wire in the following before inviting other operators to email your automation inbox.

1. SPF

  • Publish an SPF TXT record for the domain you use in CODEMAIL_MAIL_USER.
  • Example (Cloudflare → DNS): v=spf1 mx include:_spf.google.com -all – swap in the MTAs that are actually allowed to send on your behalf.

2. DKIM

  1. Install and enable OpenDKIM (or your platform’s equivalent) and generate a key pair:
    sudo opendkim-genkey -D /etc/opendkim/keys/yourdomain -d yourdomain -s mail
    sudo chown opendkim:opendkim /etc/opendkim/keys/yourdomain/mail.private
    
  2. Add a DNS TXT record named mail._domainkey.yourdomain whose value is the contents of mail.txt produced by the command above.
  3. Wire the key into Postfix by adding to /etc/opendkim/KeyTable and /etc/opendkim/SigningTable, then set in /etc/opendkim.conf:
    Domain                  yourdomain
    KeyFile                 /etc/opendkim/keys/yourdomain/mail.private
    Selector                mail
    Socket                  local:/var/spool/postfix/opendkim/opendkim.sock
    
  4. Restart OpenDKIM and Postfix, then verify DNS propagation:
    sudo systemctl restart opendkim postfix
    sudo opendkim-testkey -d yourdomain -s mail -k /etc/opendkim/keys/yourdomain/mail.private
    

3. DMARC

  1. Publish a DMARC TXT record (again via DNS) such as:
    _dmarc.yourdomain  IN  TXT  "v=DMARC1; p=quarantine; rua=mailto:dmarc@yourdomain; ruf=mailto:dmarc@yourdomain"
    
    Start with p=none if you want reports before enforcing policy.
  2. Install and enable OpenDMARC (optional but recommended). Postfix main.cf should include:
    smtpd_milters = inet:localhost:8893, inet:localhost:8891
    non_smtpd_milters = inet:localhost:8893, inet:localhost:8891
    
    (with 8893 as OpenDMARC and 8891 as OpenDKIM, adjust to match your install).
  3. Watch the reports sent to the rua address—you can move to p=reject once you are satisfied that only authorized hosts are sending mail.

4. Allowed Sender List (Codemail)

  • Use CODEMAIL_ALLOWED_SENDERS to whitelist trusted operators (example: branch@branch.bet,nrsander@gmail.com). Codemail politely rejects everyone else so you are aware of attempted usage.

Tip: if you deploy Codemail on a fresh host, put the DKIM key, DMARC TXT, and allowed sender list into infrastructure-as-code or scripts so future reinstalls stay consistent.

Development

source .venv/bin/activate
pip install -e .
ruff format src tests
ruff check src tests
pytest

Troubleshooting & FAQ

  • Getting two emails per task? Make sure the prompt hasn’t been modified—Codemail’s default instructs the agent not to send extra mail unless the task explicitly requires it.
  • Runner exits with status 75? Check that the wrapper can read .env and that the SMTP credentials are valid.
  • Want multiple configurations? Create separate .env files and wrapper scripts, then point different aliases at each.

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

codemail-0.1.1.tar.gz (16.3 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

codemail-0.1.1-py3-none-any.whl (15.1 kB view details)

Uploaded Python 3

File details

Details for the file codemail-0.1.1.tar.gz.

File metadata

  • Download URL: codemail-0.1.1.tar.gz
  • Upload date:
  • Size: 16.3 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.3

File hashes

Hashes for codemail-0.1.1.tar.gz
Algorithm Hash digest
SHA256 dfca1a7e104bdc593d1f44b0412ceeeec5baf0b514f03312727ff29f86a60301
MD5 9119262cc6ec6b5722cb62b5aa0ac356
BLAKE2b-256 304e67e1ad70e05eba99cf04e5e0f960b371c2ecefe3ce8ff962d39d6f8483e9

See more details on using hashes here.

File details

Details for the file codemail-0.1.1-py3-none-any.whl.

File metadata

  • Download URL: codemail-0.1.1-py3-none-any.whl
  • Upload date:
  • Size: 15.1 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.3

File hashes

Hashes for codemail-0.1.1-py3-none-any.whl
Algorithm Hash digest
SHA256 6fdbe83c574748719a5e3ab685bd8abd97aae3633e31603b8bbc2ad8d4a4e95d
MD5 92fbcb27aa4467b67344eab5bd5d1a74
BLAKE2b-256 41d80011e269dd0a246931032ef87390582c588ee4a030cdfbaf2129276760fe

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page