← Back to documentation

Shell Script: Pipe to Email with PayloadRelay

Use a Bash script to send command output or text to a PayloadRelay endpoint.

2 min read

Build a shell utility that sends text to email through PayloadRelay. Pipe command output, send a short message, or forward a log extract from the terminal.

Purpose#

Use this guide to:

  • Create a pr-email script that sends standard input or arguments to a PayloadRelay endpoint.
  • Pipe command output to email.
  • Set the subject, the format, and the recipient options.
  • Install the script for general use.

Before you start#

  • Create a PayloadRelay endpoint that accepts POST with the JSON or Plain text payload format.
  • Attach a confirmed email target to the endpoint.
  • Install curl and jq on the system.
  • Use Bash 4 or later. Bash is included in most Linux distributions and is available with Homebrew on macOS.

Procedure#

1. Create the endpoint#

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

2. Basic script#

Create a file with the name 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#

This extended version adds timestamps, the host name, 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 the export to ~/.bashrc or ~/.zshrc:

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"
Installation test
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 commands that take a long time
# 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#

  • pr-email is executable and available in PATH.
  • echo "test" | pr-email "Test" sends an email and prints ✓ Sent: Test.
  • The piped command output arrives in the email body.
  • A request appears in PayloadRelay Request activity as Completed (ACCEPTED).

Common issues#

  • command not found: pr-email: Make sure that the script is executable and that its location is in PATH.
  • Error: No body provided: Pipe input to the script, or use the -b flag to give a body.
  • jq: command not found: Install jq, for example with brew install jq on macOS or apt install jq on Ubuntu.
  • Failed (HTTP 401): Set PAYLOADRELAY_TOKEN, or use -t for an authenticated endpoint.
  • The email contains only part of a large output: PayloadRelay limits the payload size for each plan. Pipe the output through head or tail to make it smaller.