Posted on
Artificial Intelligence

Artificial Intelligence Email Productivity

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

Turn Your Linux Terminal Into an AI Email Productivity Machine

If you’re drowning in email, you’re not alone. Knowledge workers can spend hours every day reading, triaging, summarizing, and replying to messages. That’s a lot of repetitive, semi-structured text—exactly the kind of work modern AI models are surprisingly good at. The best part? You can run these workflows right from your Linux shell and wire them into the tools you already use.

In this guide, you’ll learn how to:

  • Summarize unread emails into a daily digest

  • Draft smart, on-tone replies with one command

  • Auto-triage messages with tags like action/read_later/archive

  • Extract tasks and due dates into structured lists (or Taskwarrior)

You’ll get working Bash snippets, package install commands for apt/dnf/zypper, and tips for running models locally (privacy-friendly) or in the cloud (no GPU needed).


Why do this in Bash?

  • Email is text; Bash is great at text. Combine IMAP sync, indexing, and AI with simple pipelines.

  • Repeatable and scriptable. Once you trust a workflow, run it from cron, systemd timers, or hotkeys.

  • Privacy and control. Use a local model with ollama, or a cloud API with explicit redaction rules.

  • Measurable value. Even a 15–30% reduction in reading and drafting time per day compounds quickly.


Prerequisites and installation

We’ll use standard command-line tools:

  • IMAP sync: isync (mbsync)

  • Index and search: notmuch

  • Utilities: ripgrep (rg), jq, curl

  • Optional sending: msmtp

  • Optional local AI: ollama

  • Optional tasks: Taskwarrior

Install the core tools:

Ubuntu/Debian (apt):

sudo apt update
sudo apt install -y isync notmuch ripgrep jq curl msmtp

Fedora/RHEL/CentOS (dnf):

sudo dnf install -y isync notmuch ripgrep jq curl msmtp

openSUSE (zypper):

sudo zypper refresh
sudo zypper install -y isync notmuch ripgrep jq curl msmtp

Optional: Taskwarrior

  • Ubuntu/Debian (apt):
sudo apt install -y taskwarrior
  • Fedora/RHEL/CentOS (dnf):
sudo dnf install -y task
  • openSUSE (zypper):
sudo zypper install -y taskwarrior

Optional: Local model with ollama (single script installer; not via apt/dnf/zypper)

curl -fsSL https://ollama.com/install.sh | sh
sudo systemctl enable --now ollama
# Pull a model (choose one):
ollama pull llama3:8b
# or
ollama pull mistral:7b

Tip: Local models keep content on your machine. Cloud models are often stronger/lower-latency. You can support both with a switch in your scripts.


Minimal IMAP sync and index

1) Configure isync (mbsync) for your inbox (Maildir). Create ~/.mbsyncrc:

IMAPAccount work
Host imap.example.com
User you@example.com
PassCmd "pass show email/you@example.com"
SSLType IMAPS

IMAPStore work-remote
Account work

MaildirStore work-local
Path ~/.mail/work/
Inbox ~/.mail/work/INBOX

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

2) Run a sync and index:

mbsync work-inbox
notmuch new

Now your messages live in ~/.mail/work and are indexed by notmuch.


Choose your AI runner (cloud or local)

Export credentials for a cloud API (example: OpenAI-compatible endpoint):

export OPENAI_API_KEY="sk-your-key"
export OPENAI_MODEL="gpt-4o-mini"   # pick any available compatible model

Or use a local model with ollama:

export OLLAMA_MODEL="llama3:8b"     # or mistral:7b, qwen2:7b, etc.

A tiny helper for Bash scripts:

ai_call() {
  # Usage: ai_call "your prompt here"
  if [ -n "$OPENAI_API_KEY" ]; then
    curl -sS https://api.openai.com/v1/chat/completions \
      -H "Authorization: Bearer $OPENAI_API_KEY" \
      -H "Content-Type: application/json" \
      -d "$(jq -n --arg m "${OPENAI_MODEL:-gpt-4o-mini}" --arg p "$1" '{
            model:$m, temperature:0.2,
            messages:[{role:"user",content:$p}]
          }')" \
    | jq -r '.choices[0].message.content'
  else
    # Local, via ollama
    ollama run "${OLLAMA_MODEL:-llama3:8b}" -p "$1"
  fi
}

Note: If you use a different cloud provider, adapt the curl call to their API.


Workflow 1: Daily AI digest of unread emails

Create ai-email-digest.sh:

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

LIMIT="${LIMIT:-20}"
QUERY="${QUERY:-tag:unread and tag:inbox}"

# Ensure mailbox is synced and indexed first (optional, uncomment if desired)
# mbsync work-inbox
# notmuch new

EMAILS=$(notmuch show --format=text --entire-thread=false --body=true --exclude=false --limit "$LIMIT" "$QUERY")

PROMPT=$(cat <<'EOF'
You are an assistant that writes a concise daily email digest.
Summarize the following emails into:

- Key highlights (3–7 bullets)

- Action items (who, what, when if stated)

- FYIs

- Risks or deadlines

Rules:

- Be accurate, terse, and specific.

- Include sender and subject snippets when helpful.

- If dates or commitments are mentioned, capture them.
Here are the raw emails delimited by:
=== EMAILS START ===
EOF
)
PROMPT="$PROMPT
=== EMAILS START ===
$EMAILS
=== EMAILS END ==="

ai_call "$PROMPT"

Run it:

chmod +x ai-email-digest.sh
./ai-email-digest.sh > ~/email-digest-$(date +%F).md

Tip: Add to cron/systemd timer each morning.


Workflow 2: One-command smart reply drafts

Draft a reply that’s on-tone and ready for review. Save ai-reply.sh:

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

if [ $# -lt 1 ]; then
  echo "Usage: $0 <notmuch-query or path-to-.eml>"
  exit 1
fi

# Get the message text either from notmuch or a file
if [ -f "$1" ]; then
  BODY=$(awk 'BEGIN{h=1} h && /^$/ {h=0;next} !h {print}' "$1")
else
  BODY=$(notmuch show --format=text --entire-thread=false --body=true --exclude=false --limit 1 "$1")
fi

STYLE=${STYLE:-"polite, concise, professional"}
SIGNOFF=${SIGNOFF:-"Best regards,\nYour Name"}
INSTRUCTIONS=${INSTRUCTIONS:-"Acknowledge the sender’s main point, answer questions directly, propose next steps if any, keep to 5–10 sentences."}

PROMPT=$(cat <<EOF
Compose a reply email in the following style: $STYLE
Instructions: $INSTRUCTIONS
Do not include extraneous commentary or placeholders. Output only the email body.
If details are missing, ask a brief clarifying question at the end.
Original message:
---
$BODY
---
Include this signoff:
$SIGNOFF
EOF
)

DRAFT=$(ai_call "$PROMPT")
OUT="reply-$(date +%s).txt"
printf "%s\n" "$DRAFT" > "$OUT"
${EDITOR:-nano} "$OUT"

Examples:

./ai-reply.sh 'tag:unread AND from:client@example.com'
# or
./ai-reply.sh ~/Downloads/message.eml

Optional sending (configure msmtp in ~/.config/msmtp/config), then:

msmtp --read-envelope-from --read-recipients < "$OUT"

Workflow 3: Auto-triage with tags (action/read_later/archive/meeting)

Tag messages so search and follow-up are trivial. Save ai-triage.sh:

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

LIMIT="${LIMIT:-30}"
QUERY="${QUERY:-tag:unread and tag:inbox}"

# Get JSON with message metadata for better prompts
MSG_JSON=$(notmuch show --format=json --entire-thread=false --body=true --limit "$LIMIT" "$QUERY")

PROMPT=$(cat <<'EOF'
You are labeling emails into exactly one of:

- action (I must do something soon)

- read_later (informational; low priority)

- archive (safe to archive; no action required)

- meeting (scheduling or calendar-related)

Return JSON array of objects: [{id, subject, from, label}], where id is the notmuch message id.

Here are emails in JSON (fields: id, headers, body):
EOF
)
PROMPT="$PROMPT
$MSG_JSON
"

RAW=$(ai_call "$PROMPT")

# Parse and apply tags
echo "$RAW" | jq -cr '.[]' | while read -r row; do
  id=$(echo "$row" | jq -r '.id')
  label=$(echo "$row" | jq -r '.label' | tr '[:upper:]' '[:lower:]')
  case "$label" in
    action) notmuch tag +action -unread id:"$id" ;;
    read_later) notmuch tag +read_later -unread id:"$id" ;;
    archive) notmuch tag +archivable -unread id:"$id" ;;
    meeting) notmuch tag +meeting -unread id:"$id" ;;
    *) notmuch tag +review -unread id:"$id" ;; # fallback
  esac
  echo "Tagged $id -> $label"
done

Run:

chmod +x ai-triage.sh
./ai-triage.sh

Now you can quickly list next actions:

notmuch search tag:action

Workflow 4: Extract tasks and due dates into structured data (or Taskwarrior)

Save ai-tasks.sh:

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

LIMIT="${LIMIT:-50}"
QUERY="${QUERY:-tag:action or subject:due or subject:deadline or tag:unread}"

TEXT=$(notmuch show --format=text --entire-thread=false --body=true --exclude=false --limit "$LIMIT" "$QUERY")

PROMPT=$(cat <<'EOF'
Extract tasks from the following emails.
Return strict JSON with: tasks: [{description, due_date (YYYY-MM-DD or null), source_hint}]
Rules:

- One task per actionable item.

- Keep descriptions short and imperative.

- Guess due_date only if explicit or strongly implied; else null.

Emails:
===
EOF
)
PROMPT="$PROMPT
$TEXT
==="

JSON=$(ai_call "$PROMPT")

# Save and optionally push into Taskwarrior
echo "$JSON" | jq . > tasks-$(date +%F).json
echo "$JSON" | jq -cr '.tasks[] | [.description, .due_date, .source_hint] | @tsv' | while IFS=$'\t' read -r desc due src; do
  if command -v task >/dev/null 2>&1; then
    if [ "$due" != "null" ] && [ -n "$due" ]; then
      task add "[$src] $desc" due:"$due"
    else
      task add "[$src] $desc"
    fi
  else
    printf "- %s%s [%s]\n" "$desc" "${due:+ (due $due)}" "$src" >> tasks.md
  fi
done

echo "Tasks captured. See tasks.json or tasks.md / Taskwarrior."

Run:

chmod +x ai-tasks.sh
./ai-tasks.sh

Reliability, privacy, and cost tips

  • Keep prompts deterministic: temperature 0.0–0.3.

  • Ask for strict JSON; validate with jq before acting.

  • Redact sensitive content for cloud calls, or prefer a local model for confidential mail.

  • Batch carefully: long threads can exceed context windows; summarize first, then act.

  • Log inputs/outputs for a while; revert any mis-tags with notmuch tag -action id:...


Conclusion and next step

Email doesn’t have to be a daily energy drain. With a few packages and small Bash scripts, you can turn AI into a reliable inbox co-pilot: summarize, triage, draft, and extract tasks—all from your terminal.

Your next step:

  • Install the prerequisites (apt/dnf/zypper above)

  • Pick a model path (local with ollama or cloud with OPENAI_API_KEY)

  • Drop the scripts into ~/bin, run them on a small batch, and iterate on prompts

Once you trust the results, schedule them. Tomorrow morning’s inbox can already be lighter.