Posted on
Artificial Intelligence

Artificial Intelligence Email Automation

Author
  • User
    linuxbash
    Posts by this author
    Posts by this author

Bash-Powered AI Email Automation on Linux: Summarize, Triage, and Draft Replies

Drowning in email? If your inbox drives your day more than your calendar, you’re not alone. The average knowledge worker spends hours per week sorting newsletters, triaging customer queries, and drafting repetitive replies. Good news: you can automate the boring parts with a few shell tools and an AI model—without abandoning your Linux workflow.

This guide shows how to:

  • Pull mail locally via IMAP

  • Summarize and auto-label new messages

  • Draft sensible replies you can review before sending

  • Schedule everything with cron or systemd—using only Bash, curl, and friends

You’ll get practical, copy-pasteable scripts and install commands for apt, dnf, and zypper.

Why AI Email Automation is Worth It

  • Time and focus: Reduce manual triage by 50–80% with smart summaries, priority flags, and labels.

  • Consistency: Drafts follow policy, tone, and formatting guidelines you define.

  • Works with your stack: Uses open protocols (IMAP/SMTP) and plain text tools you can audit.

  • Privacy control: Run everything locally on your machine; redact sensitive bits before they hit an external model; keep a human in the loop for sends.

What You’ll Build (Overview)

  • A local Maildir mirror (via isync/mbsync)

  • An indexer and searcher (notmuch)

  • A sender (msmtp)

  • A small Bash function that talks to an AI model (via curl + JSON)

  • A few scripts that:

    • Summarize and auto-label new mail
    • Draft reply templates for your review
    • Run on a schedule

1) Install prerequisites

Packages: curl, jq, isync, notmuch, msmtp, swaks, inotify-tools, and cron.

Debian/Ubuntu (apt):

sudo apt update
sudo apt install -y curl jq isync notmuch msmtp swaks inotify-tools cron

Fedora/RHEL/CentOS Stream (dnf):

sudo dnf install -y curl jq isync notmuch msmtp swaks inotify-tools cronie

openSUSE (zypper):

sudo zypper refresh
sudo zypper install -y curl jq isync notmuch msmtp swaks inotify-tools cron

Notes:

  • On Fedora, “cron” is provided by cronie.

  • Ensure your user is allowed to run cron jobs, or use systemd user timers (shown later).

2) Sync your email locally with isync (mbsync)

Create a Maildir and an mbsync config. This mirrors your IMAP account locally, which lets notmuch and Bash do fast, private processing.

~/.mbsyncrc:

IMAPAccount myacct
Host imap.example.com
User your.name@example.com
Pass your_imap_app_password
SSLType IMAPS

IMAPStore remote-myacct
Account myacct

MaildirStore local-myacct
Path ~/.mail/myacct/
Inbox ~/.mail/myacct/INBOX
SubFolders Verbatim

Channel myacct-inbox
Master :remote-myacct:INBOX
Slave :local-myacct:INBOX
Patterns *
Create Both
Expunge Both
SyncState *

Make directories and run a first sync:

mkdir -p ~/.mail/myacct/INBOX
chmod 700 ~/.mail
mbsync -a

Index with notmuch:

notmuch setup   # follow prompts, point it at ~/.mail
notmuch new

Security tip: protect credentials with file permissions:

chmod 600 ~/.mbsyncrc

3) Configure outbound mail with msmtp

~/.config/msmtp/config:

defaults
auth on
tls on
logfile ~/.msmtp.log

account default
host smtp.example.com
port 587
from your.name@example.com
user your.name@example.com
password your_smtp_app_password

Permissions:

chmod 600 ~/.config/msmtp/config

Test SMTP:

echo -e "Subject: msmtp test\n\nHello from msmtp." | msmtp -t your.name@example.com
swaks --server smtp.example.com --port 587 --au your.name@example.com --ap your_smtp_app_password --to your.name@example.com --from your.name@example.com --tls

4) Talk to an AI model from Bash

You can use any OpenAI-compatible endpoint. Set three environment variables:

  • AI_BASE_URL: base URL, e.g. https://api.openai.com

  • AI_MODEL: model name, e.g. gpt-4o-mini

  • AI_API_KEY: your API key

~/.profile (or your shell rc file):

export AI_BASE_URL="https://api.openai.com"
export AI_MODEL="gpt-4o-mini"
export AI_API_KEY="sk-your-key"

A safe, reusable Bash function to send prompts and get text results:

~/bin/ai_chat.sh:

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

prompt="$1"

if [[ -z "${AI_BASE_URL:-}" || -z "${AI_MODEL:-}" || -z "${AI_API_KEY:-}" ]]; then
  echo "AI_BASE_URL, AI_MODEL, AI_API_KEY must be set" >&2
  exit 1
fi

json_payload=$(jq -n --arg model "$AI_MODEL" --arg content "$prompt" '{
  model: $model,
  messages: [
    {role: "system", content: "You are a helpful assistant that writes JSON and concise email summaries."},
    {role: "user", content: $content}
  ],
  temperature: 0.2
}')

curl -sS \
  -H "Authorization: Bearer $AI_API_KEY" \
  -H "Content-Type: application/json" \
  -d "$json_payload" \
  "$AI_BASE_URL/v1/chat/completions" \
| jq -r '.choices[0].message.content'

Make it executable:

chmod +x ~/bin/ai_chat.sh

Tip: For privacy, redact or truncate long emails before sending to the model. Example helper:

~/bin/redact_body.sh:

#!/usr/bin/env bash
set -euo pipefail
# Read message body from stdin, trim to 4000 chars, collapse numbers.
body=$(cat)
body=${body:0:4000}
# Replace long numbers/emails with tokens
echo "$body" \
  | sed -E 's/[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}/[EMAIL]/g' \
  | sed -E 's/[0-9]{6,}/[NUMBER]/g'
chmod +x ~/bin/redact_body.sh

5) Automations you can actually use

Below are three scripts that work together. They rely on notmuch to extract text and identify messages.

A) Summarize and auto-label new mail

  • Fetch new mail

  • Summarize the body

  • Get structured JSON with tags and urgency

  • Tag messages in notmuch

~/bin/ai_summarize_and_tag.sh:

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

# 1) Sync and index
mbsync -a
notmuch new >/dev/null

# 2) Find recent unread messages (limit to 25 per run)
ids=$(notmuch search --output=messages --format=text 'tag:unread' | head -n 25)

for id in $ids; do
  # Extract plain text from the message
  text=$(notmuch show --format=text --entire-thread=false --exclude=false id:"$id" \
    | ~/bin/redact_body.sh)

  # Build a JSON-instruction prompt
  read -r -d '' prompt <<'EOF' || true
You are labeling and summarizing an email for a busy engineer.
Return only JSON with keys: summary, urgency (low|normal|high), tags (array of short strings).

Guidelines:

- tags: choose from ["billing","support","customers","recruiting","newsletter","internal","sales","legal","ops","personal"] or add at most 2 new ones if necessary.

- Keep summary <= 60 words. Be factual.
EOF

  # Combine with the email body
  full_prompt="$prompt

Email:
$text"

  # 3) Ask the model for JSON
  result=$(~/bin/ai_chat.sh "$full_prompt")

  # 4) Parse JSON and apply tags
  summary=$(printf "%s" "$result" | jq -r '.summary // empty' || true)
  urgency=$(printf "%s" "$result" | jq -r '.urgency // "normal"' || true)
  mapfile -t tags < <(printf "%s" "$result" | jq -r '.tags[]?' || true)

  # Always tag a safe prefix for AI work
  to_apply="+ai-processed"
  case "$urgency" in
    high) to_apply="$to_apply +urgent" ;;
    low)  to_apply="$to_apply -urgent" ;;
    *)    : ;;
  esac

  for t in "${tags[@]:-}"; do
    # sanitize tag names
    t_clean=$(echo "$t" | tr '[:upper:] ' '[:lower:]-' | tr -cd '[:alnum:]-_:' | sed 's/^-*//;s/-*$//')
    [[ -n "$t_clean" ]] && to_apply="$to_apply +tag-$t_clean"
  done

  notmuch tag $to_apply id:"$id"

  # Store a one-line summary in notmuch as a tag for quick view (truncated)
  if [[ -n "$summary" ]]; then
    short=$(echo "$summary" | tr -s ' ' | cut -c1-80)
    # Embed as a pseudo-tag prefix; notmuch tags cannot have spaces
    k="aiS-$(echo "$short" | tr ' ' '_' | tr -cd '[:alnum:]_')"
    notmuch tag +"$k" id:"$id"
  fi

  echo "Processed: $id ($urgency) tags applied: $to_apply"
done

Run it:

~/bin/ai_summarize_and_tag.sh

Check tags:

notmuch search tag:ai-processed

B) Draft reply templates (human-in-the-loop)

  • Generates a reply draft you can edit

  • Uses thread context from notmuch

  • Sends with msmtp when you confirm

~/bin/ai_draft_reply.sh:

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

id="${1:-}"
[[ -z "$id" ]] && { echo "Usage: $0 <notmuch-id>"; exit 1; }

# Extract original message context (last message text)
orig=$(notmuch show --format=text --entire-thread=false id:"$id" | tail -n +1 | ~/bin/redact_body.sh)

read -r -d '' prompt <<'EOF' || true
You write professional, concise email replies.
Task:

- Draft a reply of 80–150 words.

- Start with a brief acknowledgment.

- Bullet any required next steps.

- Keep tone friendly and clear.

- Do not invent facts; ask for missing info.
Return only the email body text.
EOF

body=$(~/bin/ai_chat.sh "$prompt

Original message:
$orig")

# Build minimal RFC 5322 headers; pull From/To/Subject from notmuch metadata
from=$(notmuch show --format=json --entire-thread=false id:"$id" | jq -r '.[0].headers.To' | sed 's/^ *//;s/ *$//')
to=$(notmuch show --format=json --entire-thread=false id:"$id" | jq -r '.[0].headers.From' | sed 's/^ *//;s/ *$//')
subj=$(notmuch show --format=json --entire-thread=false id:"$id" | jq -r '.[0].headers.Subject' | sed 's/^Re: */Re: /;t;s/^/Re: /')

tmp="$(mktemp /tmp/reply-XXXXXX.eml)"
{
  echo "From: $from"
  echo "To: $to"
  echo "Subject: $subj"
  echo "MIME-Version: 1.0"
  echo "Content-Type: text/plain; charset=UTF-8"
  echo
  echo "$body"
} > "$tmp"

${EDITOR:-vi} "$tmp"

read -rp "Send this email via msmtp? [y/N] " ans
if [[ "$ans" =~ ^[Yy]$ ]]; then
  msmtp -t < "$tmp" && echo "Sent."
else
  echo "Aborted. Draft at $tmp"
fi

Use it:

id=$(notmuch search --output=messages 'tag:ai-processed and tag:tag-customers' | head -n1)
~/bin/ai_draft_reply.sh "$id"

C) End-to-end triage runner

Combine sync, summarize, and a simple routing rule:

#!/usr/bin/env bash
set -euo pipefail
mbsync -a
notmuch new >/dev/null
~/bin/ai_summarize_and_tag.sh

# Example: auto-file newsletters
for id in $(notmuch search --output=messages 'tag:ai-processed and tag:tag-newsletter'); do
  notmuch tag +inbox- -unread id:"$id"
done

# Example: surface urgent items
echo "Urgent:"
notmuch search 'tag:urgent and tag:unread' | head

6) Schedule it

Cron (system-wide):

crontab -e

Add:

*/10 * * * * PATH="$HOME/bin:/usr/local/bin:/usr/bin" /bin/bash -lc '~/bin/ai_summarize_and_tag.sh' >> ~/.ai-mail.log 2>&1

Fedora note: make sure cronie is running:

sudo systemctl enable --now crond

Or use a systemd user timer:

~/.config/systemd/user/ai-mail.service:

[Unit]
Description=AI mail triage

[Service]
Type=oneshot
ExecStart=/bin/bash -lc '~/bin/ai_summarize_and_tag.sh'

~/.config/systemd/user/ai-mail.timer:

[Unit]
Description=Run AI mail triage every 10 minutes

[Timer]
OnBootSec=2m
OnUnitActiveSec=10m
Unit=ai-mail.service

[Install]
WantedBy=default.target

Enable:

systemctl --user daemon-reload
systemctl --user enable --now ai-mail.timer

Real-world patterns that work well

  • Priority triage: Tag customer domains as high priority; auto-bucket newsletters and promos.

  • Support queues: Generate short summaries and probable intent (billing vs. bug) to route tickets faster.

  • Recruiting: Draft polite declines or info requests at scale, with a human reviewing before send.

  • Sales follow-ups: Create concise next-step templates that sales can personalize.

Safety, privacy, and quality tips

  • Secrets: Keep API keys and SMTP/IMAP passwords in files with 600 permissions. Consider password managers (pass, secret-tool) with msmtp’s passwordeval.

  • Redaction: Use redact_body.sh (or expand it) to strip sensitive identifiers.

  • Human-in-the-loop: Always review drafts before sending—especially legal, finance, or HR topics.

  • Rate limits and costs: Batch processing (25 at a time) and short prompts keep usage predictable.

  • Logging: Log outcomes, not message contents, if you care about incident forensics.

Conclusion and Next Steps

You don’t need a new SaaS or GUI client to make email manageable. With Bash, isync, notmuch, msmtp, and a single AI endpoint, you can:

  • Summarize and label new mail

  • Surface urgent messages quickly

  • Draft high-quality replies in seconds

Next steps:

  • Install the prerequisites with your package manager.

  • Drop the scripts into ~/bin and try a dry run on a test mailbox.

  • Tune tags, prompts, and thresholds to your workflow.

Got a unique workflow or a thorny mail pipeline? Extend these scripts—Bash, notmuch, and AI are wonderfully composable.