← Back to documentation

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-email script 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 POST with JSON or Plain text payload format.
  • A confirmed email target attached to the endpoint.
  • curl and jq installed on the system.
  • Bash 4+ (default on most Linux distributions, available via Homebrew on macOS).

Step-by-step workflow

1. Create the endpoint

  1. Open Endpoints and select Create endpoint.
  2. Set the accepted method to POST.
  3. Set payload format to JSON.
  4. In Target destinations, attach your confirmed email target.
  5. Save and copy the endpoint URL.

2. Basic script

Create a file called pr-email:

Code Example
#!/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
fi

3. Usage examples

Pipe command output
# 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"
Direct body
# 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"
With a custom endpoint
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:

Code Example
#!/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
fi

5. Installation

Make executable and add to PATH
# 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 ~/.bashrc

Add to your shell profile (~/.bashrc, ~/.zshrc, etc.):

Set the default endpoint
export PAYLOADRELAY_ENDPOINT="https://api.payloadrelay.com/relay/YOUR_ENDPOINT_ID"

# Optional: if your endpoint requires auth
export PAYLOADRELAY_TOKEN="your-bearer-token"
Verify installation
echo "Installation test" | pr-email "pr-email Test"

6. Practical recipes

Cron job with email report
# 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"
After long-running commands
# 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"
Error alerting in scripts
#!/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
Combining with other tools
# 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-email is 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 activity with outcome ACCEPTED.

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 -b flag to provide a body.
  • jq: command not found: install jq (brew install jq on macOS, apt install jq on Ubuntu).
  • Failed (HTTP 401): set PAYLOADRELAY_TOKEN or use -t for authenticated endpoints.
  • Large output truncated in email: PayloadRelay has payload size limits per plan. Pipe through head or tail to limit output size.

Related guides