Secure msmtp Setup: TLS, Authentication, and Best Practices

Automate Email Sending with msmtp and CronAutomating email sending on a Unix-like system is useful for notifications, backups, monitoring alerts, and scheduled reports. This guide shows how to configure msmtp — a lightweight SMTP client — and use cron to send emails automatically. It covers installation, configuration, secure authentication, composing messages, scheduling with cron, and troubleshooting.


What is msmtp?

msmtp is a simple SMTP client that forwards mail from local programs (like mailx, mutt, or custom scripts) to an external SMTP server. It is lightweight, easy to configure, and supports TLS/SSL and authentication mechanisms required by modern SMTP servers (e.g., Gmail, Outlook, corporate SMTP). Unlike full mail transfer agents (MTAs) such as Postfix or Exim, msmtp does not queue or accept incoming mail — it simply relays outgoing messages.


Why use msmtp + cron?

  • Minimal resource usage compared to full MTAs.
  • Straightforward configuration and integration with scripts.
  • Works well for automated notifications (backup completion, system health checks, CI/CD).
  • Cron provides reliable time-based scheduling available on virtually all Unix-like systems.

Installation

On Debian/Ubuntu:

sudo apt update sudo apt install msmtp msmtp-mta 

On Fedora:

sudo dnf install msmtp msmtp-mta 

On Arch:

sudo pacman -S msmtp 

On macOS (Homebrew):

brew install msmtp 

msmtp-mta provides a symlink so programs expecting sendmail can call msmtp.


msmtp configuration

msmtp reads configuration from /etc/msmtprc (system-wide) and ~/.msmtprc (per-user). File permissions should be restricted to the owner (600).

Example ~/.msmtprc with TLS and login authentication:

# ~/.msmtprc # Set default account defaults auth           on tls            on tls_trust_file /etc/ssl/certs/ca-certificates.crt logfile        ~/.msmtp.log # Account for Gmail account        gmail host           smtp.gmail.com port           587 user           [email protected] passwordeval   "gpg --quiet --for-your-eyes-only --no-tty -d ~/.mail/gmail.pass.gpg" # Set a default account account default : gmail 

Important notes:

  • Use passwordeval to avoid plaintext passwords; passwordeval runs a command and uses its stdout as the password.
  • For simple setups you can use password instead of passwordeval, but ensure ~/.msmtprc is permission 600.
  • tls_trust_file path may vary by distro: common locations include /etc/ssl/certs/ca-certificates.crt or /etc/ssl/cert.pem.

Encrypting password with GPG example:

echo -n "your_app_password" | gpg --symmetric --cipher-algo AES256 -o ~/.mail/gmail.pass.gpg chmod 600 ~/.mail/gmail.pass.gpg 

Then passwordeval example above decrypts it when msmtp runs.

For Gmail specifically:

  • If using regular account password, Gmail may block access. Use an App Password (recommended) with 2-Step Verification enabled, or configure OAuth2 (more complex).

Sending an email from the command line

msmtp expects a full RFC-5322 message on stdin. A quick way to send a simple message:

printf "From: [email protected] To: [email protected] Subject: Test from msmtp Hello from msmtp. " | msmtp [email protected] 

Using a file:

msmtp [email protected] < /path/to/message.eml 

Composing with heredoc in a script:

msmtp [email protected] <<EOF From: [email protected] To: [email protected] Subject: Backup completed Backup finished successfully at $(date). EOF 

For attachments, use a tool like mutt, mailx, or uuencode to create MIME messages, or build MIME manually.

Example with mailx (s-nail) configured to use msmtp as sendmail:

echo "Backup completed" | mailx -s "Backup report" -a /path/to/log.txt [email protected] 

Ensure mailx is configured to call msmtp (msmtp-mta package or sendmail symlink).


Integrating into scripts

Create a script that generates the message and calls msmtp.

Example backup notification script /usr/local/bin/backup-notify.sh:

#!/usr/bin/env bash set -euo pipefail RECIP="[email protected]" SUBJ="Backup finished on $(hostname)" BODY="/tmp/backup_body_$$.txt" cat > "$BODY" <<EOF From: backup@$(hostname) To: $RECIP Subject: $SUBJ Backup completed successfully. Date: $(date) EOF msmtp "$RECIP" < "$BODY" && rm -f "$BODY" 

Make it executable:

chmod +x /usr/local/bin/backup-notify.sh 

Scheduling with cron

Edit the crontab for the user who has msmtp configured:

crontab -e 

Example entries:

  • Run backup daily at 02:00 and send notification: 0 2 * * * /usr/local/bin/perform-backup.sh && /usr/local/bin/backup-notify.sh
  • Send weekly report every Monday at 07:30: 30 7 * * 1 /usr/local/bin/send-weekly-report.sh

Tips:

  • Use full paths for scripts and binaries in cron.
  • Cron environment is minimal; explicitly set PATH, HOME, and other env vars at top of crontab if needed: PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin HOME=/home/youruser
  • Log cron output to a file for debugging: 0 2 * * * /usr/local/bin/backup-notify.sh >> /var/log/backup-notify.log 2>&1

Secure authentication options

  • App Passwords: For providers like Gmail, create an App Password when 2FA is enabled and use it with msmtp.
  • GPG-encrypted password files: store SMTP password encrypted and use passwordeval to decrypt.
  • OAuth2: msmtp supports XOAUTH2 via passwordeval scripts that fetch and refresh tokens. This is more complex but removes long-term passwords from disk.

Simple passwordeval example that reads GPG-decrypted password:

passwordeval "gpg -q --for-your-eyes-only --no-tty -d ~/.mail/gmail.pass.gpg" 

Handling attachments and HTML

msmtp itself sends raw RFC-5322 messages. To include attachments or HTML you must build a MIME message. Use tools:

  • mutt or neomutt
  • mailx (s-nail)
  • msmtp + uuencode (older)
  • python (email.mime) to generate MIME

Example using mutt:

echo "See attached log" | mutt -s "Backup log" -a /var/log/backup.log -- [email protected] 

Configure mutt to use msmtp as sendmail, or ensure msmtp-mta provides sendmail compatibility.

Example using Python (script creates MIME and sends via msmtp):

#!/usr/bin/env python3 from email.message import EmailMessage import subprocess msg = EmailMessage() msg['From'] = 'backup@hostname' msg['To'] = '[email protected]' msg['Subject'] = 'Backup log' msg.set_content('See attached log.') with open('/var/log/backup.log','rb') as f:     data = f.read() msg.add_attachment(data, maintype='text', subtype='plain', filename='backup.log') # Send via msmtp proc = subprocess.Popen(['msmtp','[email protected]'], stdin=subprocess.PIPE) proc.communicate(msg.as_bytes()) 

Troubleshooting

  • Permission errors: ensure ~/.msmtprc is chmod 600 and readable only by owner.
  • TLS errors: verify tls_trust_file path and CA bundle. Use tls on and correct CA file.
  • Authentication failures: check username/password or app password; test with verbose mode: msmtp –debug –from=default -t < /path/to/message.eml
  • Connection issues: confirm firewall allows outbound SMTP (ports 587/465/25) and provider accepts connections.
  • Cron emails not being sent: capture cron stdout/stderr to a log file and run script manually to replicate.

Example: end-to-end setup for daily report

  1. Create ~/.msmtprc with encrypted password and default account.
  2. Create /usr/local/bin/send-daily-report.sh that composes a MIME message (or plain) and calls msmtp.
  3. Add cron entry: 0 8 * * * /usr/local/bin/send-daily-report.sh >> /var/log/daily-report.log 2>&1

Conclusion

msmtp plus cron provides a dependable, low-overhead solution to automate outgoing email from scripts and scheduled tasks. With proper configuration (secure passwords, TLS, and careful cron setup), you can reliably send notifications, reports, and alerts without running a full mail server.

Comments

Leave a Reply

Your email address will not be published. Required fields are marked *