How to Send Email from Bash

How to Send Email from Bash

How to Send Email from Bash

One of the most useful things I’ve automated with Bash is email alerts — a backup script that emails me if it fails, a monitoring job that reports disk usage, a cron job that sends me a daily summary. Sending email from a shell script sounds like it should be complicated, but once I understood the handful of tools available, it became one of the simplest additions to any script. Here’s everything I’ve learned about sending email from Bash.

The Tools Available

There are a few common ways to send email from a Bash script, and I pick based on what’s already installed and how much control I need:

Installing mailutils

On most Debian/Ubuntu systems:

sudo apt-get install mailutils

On RHEL/CentOS/Fedora:

sudo dnf install mailx

Beginner Example: Sending a Simple Email

echo "This is the email body" | mail -s "Test Subject" recipient@example.com

By default, this relies on a local mail transfer agent (MTA) like postfix or sendmail being installed and configured to actually deliver the message, which is often the missing piece when this “doesn’t work” on a fresh server.

Sending Email with an Attachment

echo "Please find the report attached." | mail -s "Daily Report" -A /tmp/report.pdf recipient@example.com

The -A flag (supported by mailutilsmail, spelled differently in some mailx variants) attaches a file to the message.

Step-by-Step: A Script That Emails a System Report

#!/usr/bin/env bash
set -euo pipefail

RECIPIENT="admin@example.com"
SUBJECT="Daily System Report - $(hostname) - $(date +%Y-%m-%d)"
REPORT_FILE=$(mktemp)

{
    echo "System Report for $(hostname)"
    echo "Generated: $(date)"
    echo ""
    echo "Disk Usage:"
    df -h
    echo ""
    echo "Memory Usage:"
    free -h
    echo ""
    echo "Uptime:"
    uptime
} > "$REPORT_FILE"

mail -s "$SUBJECT" "$RECIPIENT" < "$REPORT_FILE"

rm -f "$REPORT_FILE"

Explaining the Script Internally

Sending Email Through an External SMTP Server (Gmail Example)

Many servers don’t have a properly configured local MTA, so relaying through an external SMTP provider like Gmail, SendGrid, or Amazon SES is often more reliable. msmtp is my preferred tool for this because its configuration is straightforward.

Install it:

sudo apt-get install msmtp msmtp-mta

Configure ~/.msmtprc:

account default
host smtp.gmail.com
port 587
auth on
user your_email@gmail.com
password your_app_password
tls on
tls_starttls on
from your_email@gmail.com
logfile ~/.msmtp.log

Set proper permissions since this file contains credentials:

chmod 600 ~/.msmtprc

Send an email:

echo -e "Subject: Test via msmtp\n\nThis is the body of the email." | msmtp recipient@example.com

Note the \n\n — this separates the Subject: header from the message body, matching the raw structure of an email message (headers, blank line, body).

Real-World Use Case: Alerting on Failed Backups

#!/usr/bin/env bash
set -euo pipefail

BACKUP_DIR="/data"
DEST="/backups/backup-$(date +%Y%m%d).tar.gz"
RECIPIENT="admin@example.com"

if tar -czf "$DEST" "$BACKUP_DIR"; then
    echo "Backup succeeded: $DEST" | mail -s "Backup Success" "$RECIPIENT"
else
    echo "Backup FAILED at $(date)" | mail -s "URGENT: Backup Failure" "$RECIPIENT"
    exit 1
fi

This pattern — success email on the happy path, urgent email on failure — is one I copy into almost every unattended maintenance script I write.

Automation Example: Weekly Digest Email with HTML Formatting

Plain text is fine for alerts, but for a nicer weekly summary I send HTML email using proper MIME headers:

#!/usr/bin/env bash
set -euo pipefail

RECIPIENT="team@example.com"
SUBJECT="Weekly Server Digest"

{
    echo "To: $RECIPIENT"
    echo "Subject: $SUBJECT"
    echo "MIME-Version: 1.0"
    echo "Content-Type: text/html"
    echo ""
    echo "<html><body>"
    echo "<h2>Weekly Digest</h2>"
    echo "<p>Uptime: $(uptime -p)</p>"
    echo "<p>Disk usage:</p><pre>$(df -h)</pre>"
    echo "</body></html>"
} | msmtp -t

The -t flag tells msmtp to read the recipient(s) from the To: header inside the message itself rather than requiring it as a command-line argument.

Security Considerations

Optimization Tips

Troubleshooting

Common Mistakes to Avoid

FAQs

Do I need a local MTA installed to send email from Bash? Not necessarily — you can relay directly through an external SMTP server using msmtp or ssmtp, which avoids needing to configure a full mail server like Postfix locally.

Can I send email with attachments using msmtp? msmtp itself doesn’t handle MIME attachment encoding; combine it with mutt or construct the MIME multipart message manually if attachments are needed.

Is it safe to use Gmail’s SMTP for automated scripts? Yes, with an app-specific password and TLS enabled, though be aware Gmail enforces sending limits that may not suit high-volume automated alerts.

How do I test email sending without spamming a real inbox? Tools like mailhog or mailtrap.io provide fake SMTP servers for testing that capture emails without actually delivering them anywhere.

Summary

Sending email from Bash is a small addition that makes scripts dramatically more useful — turning a silent cron job into something that actively tells you when it succeeds, fails, or needs attention. Whether through a simple mail command backed by a local MTA or a proper SMTP relay via msmtp, the pattern is the same: build the message, set the right headers, and let the tool handle delivery, while keeping credentials and content secure along the way.

References

Exit mobile version