Skip to content

Guides

Scripting and automation

Use Mailfire from shell scripts, cron, and CI with stable exit codes, JSON output, environment configuration, and a send log.

Mailfire is designed to run unattended: it never prompts, never reads interactively from a terminal, and reports every outcome through its exit code.

Exit codes

CodeMeaning
0Success, including a repeat skipped by --dedup-key
1Usage error
2Configuration error
3Authentication error
4Send failed, message deferred for mailfire resend
5Send failed, message not deferred
mailfire --to ops@example.com --subject "Backup failed" --file backup.log
rc=$?
case $rc in
  0) ;;                                   # sent (or skipped as a repeat)
  4) logger "mail deferred; mailfire resend will retry" ;;
  *) logger "mail failed with exit code $rc" ;;
esac

See Exit codes for the details of each command.

JSON output

Add --json to send, resend (including --list), queue list|show|delete|stats, validate, auth status|refresh|logout, version, or export-templates to get exactly one JSON document on stdout instead of the human-readable output:

mailfire --json --to ops@example.com --subject "Backup done" --message "ok" | jq -r .message_id
mailfire resend --json | jq '.summary'
mailfire queue list --json | jq -r '.messages[] | select(.status == "failed") | .id'

Every document has schema_version, command, outcome, and exit_code; failures add an error object with a stable code such as auth_failed. Diagnostics and warnings stay on stderr, exit codes are unchanged, and --help always prints text. Credentials and message content are never included, except the stored request with queue show --raw --json. The JSON output reference documents every field, error code, and the compatibility guarantees.

Configuration without a file

In CI pipelines and containers, supply the configuration through MAILFIRE_* environment variables instead of a file:

export MAILFIRE_MAILGUN_API_KEY="<your-api-key>"   # from your CI secret store
export MAILFIRE_MAILGUN_REGION="eu"
export MAILFIRE_SENDING_DOMAIN="example.com"
export MAILFIRE_SENDING_FROM="CI <ci@example.com>"
mailfire --to dev@example.com --subject "Build finished" --message "All tests passed."

See Environment variables for every variable and the precedence rules.

Cron

Cron runs with a minimal environment and PATH. Use the full path of the binary (command -v mailfire prints it), and pass -c when the configuration is not in a default location:

# Daily report at 07:00; retry deferred messages every five minutes.
0 7 * * *   /usr/local/bin/mailfire -c /etc/mailfire/mailfire.conf --md --to ops@example.com --subject "Daily report" --file /var/reports/daily.md
*/5 * * * * /usr/local/bin/mailfire -c /etc/mailfire/mailfire.conf resend

Pair recurring alerts with --dedup-key so a persistent problem is reported once per cooldown.

Timeouts

Provider requests time out after 30 seconds by default. Set timeout in the provider’s section ([mailgun], [smtp], or [gmail]), or pass --timeout <duration> (for example 15s or 1m) on send, resend, and validate; the flag overrides the setting. A resend run retrying several messages may take longer than a single timeout.

Send log

Logging is disabled unless logfile is set in [logging]. Every sending attempt — successful or not, including test sends and resends — then appends one JSON line. The fields depend on loglevel:

LevelFields
errortimestamp, message_id, to, status — failed attempts only
information (default)timestamp, message_id, to, subject, status
debugalso from, size, and the provider’s response

status is the provider’s reply code (HTTP status, or the SMTP reply code), or 0 when no response was received. Test sends carry "test": true. Deferred messages dropped because the queue exceeded max_size, or removed after max_age, are logged at every level with "event": "defer_drop" or "defer_expire". Credentials never reach the log.

When the file exceeds max_size (default 50M), the oldest lines are removed; the newest entry is always kept.

[logging]
logfile = "~/logs/mailfire.log"
loglevel = "information"
max_size = "50M"
Edit this page on GitHub Last updated