Shell Script: Pipe to Email via PayloadRelay
Bash script that reads stdin and sends it to a PayloadRelay endpoint, enabling patterns like piping command output directly to email.
8 min read
Build a shell utility that sends text to email via PayloadRelay. Pipe command output, send quick messages, or forward log snippets — all from the terminal.
Purpose
This guide helps you:
- Create a
pr-emailscript that sends stdin or arguments to a PayloadRelay endpoint. - Pipe any command output to email.
- Configure subject, format, and recipient options.
- Install the script for system-wide use.
Prerequisites and permissions
- A PayloadRelay endpoint configured to accept
POSTwithJSONorPlain textpayload format. - A confirmed email target attached to the endpoint.
curlandjqinstalled on the system.- Bash 4+ (default on most Linux distributions, available via Homebrew on macOS).
Step-by-step workflow
1. Create the endpoint
- Open
Endpointsand selectCreate endpoint. - Set the accepted method to
POST. - Set payload format to
JSON. - In
Target destinations, attach your confirmed email target. - Save and copy the endpoint URL.
2. Basic script
Create a file called pr-email:
#!/bin/bash
set -euo pipefail
# Configuration
PAYLOADRELAY_ENDPOINT="${PAYLOADRELAY_ENDPOINT:-https://api.payloadrelay.com/relay/YOUR_ENDPOINT_ID}"
usage() {
cat <<EOF
Usage: pr-email [OPTIONS] "Subject line"
command | pr-email "Subject line"
Send text to email via PayloadRelay.
Options:
-e ENDPOINT Override the PayloadRelay endpoint URL
-b BODY Pass body as argument instead of stdin
-h Show this help message
Environment:
PAYLOADRELAY_ENDPOINT Default endpoint URL
Examples:
echo "Hello" | pr-email "Test Message"
pr-email -b "Server rebooted" "Server Alert"
df -h | pr-email "Disk Report"
EOF
exit 0
}
BODY=""
while getopts "e:b:h" opt; do
case $opt in
e) PAYLOADRELAY_ENDPOINT="$OPTARG" ;;
b) BODY="$OPTARG" ;;
h) usage ;;
*) usage ;;
esac
done
shift $((OPTIND - 1))
SUBJECT="${1:-Notification from pr-email}"
# Read from stdin if no body argument and stdin is not a terminal
if [ -z "$BODY" ] && [ ! -t 0 ]; then
BODY=$(cat)
fi
if [ -z "$BODY" ]; then
echo "Error: No body provided. Pipe input or use -b flag." >&2
exit 1
fi
# Send to PayloadRelay
RESPONSE=$(curl -s -w "\n%{http_code}" -X POST "$PAYLOADRELAY_ENDPOINT" \
-H "Content-Type: application/json" \
-d "$(jq -n --arg subject "$SUBJECT" --arg body "$BODY" \
'{subject: $subject, body: $body}')")
HTTP_CODE=$(echo "$RESPONSE" | tail -1)
RESPONSE_BODY=$(echo "$RESPONSE" | sed '$d')
if [ "$HTTP_CODE" -ge 200 ] && [ "$HTTP_CODE" -lt 300 ]; then
echo "✓ Sent: $SUBJECT"
else
echo "✗ Failed (HTTP $HTTP_CODE): $RESPONSE_BODY" >&2
exit 1
fi3. Usage examples
# Disk usage report
df -h | pr-email "Disk Report"
# System info
uname -a | pr-email "System Info"
# Docker container status
docker ps --format "table {{.Names}}\t{{.Status}}\t{{.Ports}}" | pr-email "Container Status"
# Git log
git log --oneline -10 | pr-email "Recent Commits"
# Tail logs
tail -50 /var/log/app.log | pr-email "Recent App Logs"# Quick message
pr-email -b "Deployment complete for v2.4.0" "Deploy Notification"
# Multi-line body
pr-email -b "Server: web-01
Status: rebooted
Time: $(date -u)" "Server Alert"echo "Alert content" | pr-email -e "https://api.payloadrelay.com/relay/OTHER_ENDPOINT_ID" "Custom Alert"4. Extended script with more options
A more full-featured version with timestamps, hostname, and format options:
#!/bin/bash
set -euo pipefail
PAYLOADRELAY_ENDPOINT="${PAYLOADRELAY_ENDPOINT:-https://api.payloadrelay.com/relay/YOUR_ENDPOINT_ID}"
PAYLOADRELAY_TOKEN="${PAYLOADRELAY_TOKEN:-}"
usage() {
cat <<EOF
Usage: pr-email [OPTIONS] "Subject line"
command | pr-email [OPTIONS] "Subject line"
Send text to email via PayloadRelay.
Options:
-e ENDPOINT Override the PayloadRelay endpoint URL
-t TOKEN Bearer token for authenticated endpoints
-b BODY Pass body as argument instead of stdin
-m Include machine metadata (hostname, timestamp)
-q Quiet mode (no output on success)
-h Show this help message
Environment:
PAYLOADRELAY_ENDPOINT Default endpoint URL
PAYLOADRELAY_TOKEN Default Bearer token
Examples:
echo "Hello" | pr-email "Test Message"
pr-email -b "Server rebooted" "Server Alert"
df -h | pr-email -m "Disk Report"
cat report.txt | pr-email -t mytoken "Weekly Report"
EOF
exit 0
}
BODY=""
INCLUDE_META=false
QUIET=false
while getopts "e:t:b:mqh" opt; do
case $opt in
e) PAYLOADRELAY_ENDPOINT="$OPTARG" ;;
t) PAYLOADRELAY_TOKEN="$OPTARG" ;;
b) BODY="$OPTARG" ;;
m) INCLUDE_META=true ;;
q) QUIET=true ;;
h) usage ;;
*) usage ;;
esac
done
shift $((OPTIND - 1))
SUBJECT="${1:-Notification from pr-email}"
# Read from stdin if no body argument and stdin is not a terminal
if [ -z "$BODY" ] && [ ! -t 0 ]; then
BODY=$(cat)
fi
if [ -z "$BODY" ]; then
echo "Error: No body provided. Pipe input or use -b flag." >&2
exit 1
fi
# Build JSON payload
JSON_ARGS=(--arg subject "$SUBJECT" --arg body "$BODY")
JSON_TEMPLATE='{subject: $subject, body: $body}'
if [ "$INCLUDE_META" = true ]; then
JSON_ARGS+=(
--arg hostname "$(hostname)"
--arg timestamp "$(date -u +%Y-%m-%dT%H:%M:%SZ)"
--arg user "$(whoami)"
)
JSON_TEMPLATE='{subject: $subject, body: $body, hostname: $hostname, timestamp: $timestamp, user: $user}'
fi
PAYLOAD=$(jq -n "${JSON_ARGS[@]}" "$JSON_TEMPLATE")
# Build curl arguments
CURL_ARGS=(-s -w "\n%{http_code}" -X POST "$PAYLOADRELAY_ENDPOINT"
-H "Content-Type: application/json"
-d "$PAYLOAD")
if [ -n "$PAYLOADRELAY_TOKEN" ]; then
CURL_ARGS+=(-H "Authorization: Bearer $PAYLOADRELAY_TOKEN")
fi
# Send
RESPONSE=$(curl "${CURL_ARGS[@]}")
HTTP_CODE=$(echo "$RESPONSE" | tail -1)
if [ "$HTTP_CODE" -ge 200 ] && [ "$HTTP_CODE" -lt 300 ]; then
if [ "$QUIET" != true ]; then
echo "✓ Sent: $SUBJECT"
fi
else
RESPONSE_BODY=$(echo "$RESPONSE" | sed '$d')
echo "✗ Failed (HTTP $HTTP_CODE): $RESPONSE_BODY" >&2
exit 1
fi5. Installation
# Make executable
chmod +x pr-email
# Option A: copy to a directory already in PATH
sudo cp pr-email /usr/local/bin/
# Option B: add the script's directory to PATH
echo 'export PATH="$PATH:/path/to/scripts"' >> ~/.bashrc
source ~/.bashrcAdd to your shell profile (~/.bashrc, ~/.zshrc, etc.):
export PAYLOADRELAY_ENDPOINT="https://api.payloadrelay.com/relay/YOUR_ENDPOINT_ID"
# Optional: if your endpoint requires auth
export PAYLOADRELAY_TOKEN="your-bearer-token"echo "Installation test" | pr-email "pr-email Test"6. Practical recipes
# In crontab (crontab -e):
0 9 * * 1 df -h | pr-email "Weekly Disk Report"
0 8 * * * docker ps -a --format "table {{.Names}}\t{{.Status}}" | pr-email "Daily Container Status"# Notify when a build finishes
make all 2>&1 | pr-email "Build Output"
# Notify when a backup completes
pg_dump mydb | gzip > backup.gz && pr-email -b "Backup completed: $(ls -lh backup.gz | awk '{print $5}')" "Backup Done"#!/bin/bash
set -euo pipefail
trap 'echo "Script failed at line $LINENO" | pr-email "Script Failure: $(basename $0)"' ERR
# Rest of your script...
process_data
generate_report# Send filtered logs
grep "ERROR" /var/log/app.log | tail -20 | pr-email "Recent Errors"
# Send a formatted table
ps aux --sort=-%mem | head -11 | pr-email "Top Memory Processes"
# Send JSON-formatted data
curl -s https://api.example.com/status | jq . | pr-email "API Status"Expected result and verification checks
pr-emailis executable and available in PATH.echo "test" | pr-email "Test"sends an email and prints✓ Sent: Test.- Piped command output arrives in the email body.
- Requests appear in PayloadRelay
Request activitywith outcomeACCEPTED.
Common issues and fixes
command not found: pr-email: ensure the script is executable and its location is in PATH.Error: No body provided: pipe input or use the-bflag to provide a body.jq: command not found: install jq (brew install jqon macOS,apt install jqon Ubuntu).Failed (HTTP 401): setPAYLOADRELAY_TOKENor use-tfor authenticated endpoints.- Large output truncated in email: PayloadRelay has payload size limits per plan. Pipe through
headortailto limit output size.