Sunday, 10 May 2026

Add Email Delivery for PostgreSQL HTML Index Report

With email delivery:

  • DBAs get reports without logging into servers
  • Managers can review performance easily
  • Issues are noticed early
  • Reports become part of operational workflow

We’ll use Linux mail / sendmail / mailx, which is the most common, reliable approach.


What This Will Do

Generate HTML report
Email it as HTML body (not just attachment)
Optional attachment support
Fully automated via cron
Safe for production


Prerequisites (One‑Time)

1️ Ensure Mail Utility Is Installed

Debian / Ubuntu

Shell

sudo apt install mailutils

Show more lines

RHEL / CentOS / Rocky

Shell

sudo yum install mailx

Show more lines

Assumes server can send email (SMTP configured or relay allowed).


Step 1: Decide Report Recipients

Edit once in script:

Shell

EMAIL_TO="dba@company.com,team@company.com"

EMAIL_FROM="postgres-monitor@company.com"

Show more lines


Step 2: Update HTML Report Generator Script

Below is the FULL updated script with HTML generation + email delivery.

📄 scripts/generate_index_report.sh

Shell

#!/bin/bash

 

DB="mydb"

BASE="/opt/pg_monitoring"

DATE=$(date +%F)

PSQL="/usr/bin/psql"

 

EMAIL_TO="dba@company.com"

EMAIL_FROM="postgres-monitor@company.com"

SUBJECT="PostgreSQL Index Report - $DATE"

 

HTML_OUT="$BASE/output/html/index_report_$DATE.html"

 

HEADER="$BASE/reports/html/header.html"

FOOTER="$BASE/reports/html/footer.html"

STYLE="$BASE/reports/html/style.css"

 

# ---------- HTML HEADER ----------

sed "s/{{DATE}}/$DATE/" $HEADER > $HTML_OUT

echo "<style>" >> $HTML_OUT

cat $STYLE >> $HTML_OUT

echo "</style>" >> $HTML_OUT

 

add_section () {

TITLE=$1

QUERY=$2

 

echo "<h2>$TITLE</h2>" >> $HTML_OUT

$PSQL -d $DB -H -c "$QUERY" >> $HTML_OUT

}

 

# ---------- HTML CONTENT ----------

add_section "Index Health Summary" "

SELECT

COUNT(*) AS total_indexes,

SUM(CASE WHEN idx_scan = 0 THEN 1 ELSE 0 END) AS unused_indexes,

pg_size_pretty(SUM(pg_relation_size(indexrelid))) AS total_index_size

FROM pg_stat_user_indexes;

"

 

add_section "Top 10 Largest Indexes" "

SELECT

indexrelname AS index_name,

relname AS table_name,

pg_size_pretty(pg_relation_size(indexrelid)) AS index_size,

idx_scan

FROM pg_stat_user_indexes

ORDER BY pg_relation_size(indexrelid) DESC

LIMIT 10;

"

 

add_section "Fast Growing Indexes (Last 7 Days)" "

SELECT

index_name,

pg_size_pretty(MAX(index_size_bytes) - MIN(index_size_bytes)) AS growth

FROM monitoring.index_size_history

WHERE captured_at >= now() - INTERVAL '7 days'

GROUP BY index_name

HAVING MAX(index_size_bytes) - MIN(index_size_bytes) > 100000000;

"

 

add_section "Unused Indexes" "

SELECT

indexrelname AS index_name,

relname AS table_name,

pg_size_pretty(pg_relation_size(indexrelid)) AS index_size

FROM pg_stat_user_indexes

WHERE idx_scan = 0

ORDER BY pg_relation_size(indexrelid) DESC;

"

 

add_section "GIN Indexes (High Risk)" "

SELECT

indexrelname AS gin_index,

relname AS table_name,

pg_size_pretty(pg_relation_size(indexrelid)) AS index_size,

idx_scan

FROM pg_stat_user_indexes

WHERE indexrelname ILIKE '%gin%'

ORDER BY pg_relation_size(indexrelid) DESC;

"

 

# ---------- HTML FOOTER ----------

cat $FOOTER >> $HTML_OUT

 

# ---------- EMAIL DELIVERY ----------

mail -a "Content-Type: text/html" \

-s "$SUBJECT" \

-r "$EMAIL_FROM" \

"$EMAIL_TO" < $HTML_OUT

Show more lines

Make executable (if not already):

Shell

chmod +x /opt/pg_monitoring/scripts/generate_index_report.sh

Show more lines


Step 3: Cron Job (No Change)

Your existing cron job now automatically emails the report.

Shell

0 3 * * * /opt/pg_monitoring/scripts/generate_index_report.sh

Show more lines

HTML is generated
Email is sent immediately
Zero manual steps


Step 4: What the Email Looks Like

📧 Email Subject

PostgreSQL Index Report - 2026-04-18

📄 Email Body

  • Full HTML report
  • Styled tables
  • Index risk information
  • Easy to read on desktop & mobile

No attachment required
Opens instantly
Manager‑friendly


Optional: Send as HTML Attachment Instead

If your mail server blocks HTML bodies, use attachment mode:

Shell

mail -s "$SUBJECT" \

-a "$HTML_OUT" \

"$EMAIL_TO" < /dev/null

Show more lines


Optional: Send Only If Issues Found

Add logic before sending:

Shell

ISSUES=$(grep -c "<tr>" $HTML_OUT)

 

if [ "$ISSUES" -gt 5 ]; then

mail -a "Content-Type: text/html" -s "$SUBJECT" "$EMAIL_TO" < $HTML_OUT

fi

Show more lines

Avoids alert fatigue
Sends only meaningful reports


Best Practices for Email Reports

Send once per day
Use clear subject with date
Group recipients wisely
Use HTML body, not just attachments
Keep reports under control (dont spam)


Summary

  • HTML index reports now emailed automatically
  • Works with cron
  • Uses standard Linux mail tools
  • Production‑safe and readable
  • Zero downtime impact

You now have end‑to‑end PostgreSQL index monitoring:

Collect
Analyze
Report
Email

 

No comments:

Post a Comment

Multithreading in PostgreSQL Using dblink and FDW (Reality vs Myth) First: The Critical Truth (Must Be Clear) You cannot create true mul...