---
title: Email Sending SOP
created: 2026-03-16
updated: 2026-03-16
tags: [sop, email, gmail, tools]
---

# Email Sending SOP

## Quick Reference

```bash
node /home/ccuser/rateright-growth/scripts/send-email.js \
  --to "recipient@example.com" \
  --subject "Subject" \
  --body "Message body"
```

Sends as: **Michael McLoughlin <michael@rateright.com.au>**

## Usage

### Plain text email
```bash
node /home/ccuser/rateright-growth/scripts/send-email.js \
  --to "someone@example.com" \
  --subject "Subject here" \
  --body "Message here"
```

### With PDF attachment
```bash
node /home/ccuser/rateright-growth/scripts/send-email.js \
  --to "someone@example.com" \
  --subject "See attached" \
  --body "Here's the document" \
  --attachment /path/to/file.pdf
```

### Multiple recipients (comma-separated)
```bash
node /home/ccuser/rateright-growth/scripts/send-email.js \
  --to "a@x.com,b@x.com,c@x.com" \
  --subject "Update" \
  --body "Hey team"
```

### Piped JSON (programmatic use)
```bash
echo '{"to":"a@x.com","subject":"Hi","body":"Message"}' | \
  node /home/ccuser/rateright-growth/scripts/send-email.js --stdin
```

### Custom sender
```bash
node /home/ccuser/rateright-growth/scripts/send-email.js \
  --to "someone@example.com" \
  --subject "Hi" \
  --body "Message" \
  --from "Team RateRight <team@rateright.com.au>"
```

### Dry run (test without sending)
```bash
node /home/ccuser/rateright-growth/scripts/send-email.js \
  --to "someone@example.com" \
  --subject "Test" \
  --body "Test" \
  --dry-run
```

## Output

Returns JSON to stdout for programmatic parsing:
```json
{"to":"someone@example.com","status":"sent","id":"19cf5af1132382df"}
```

Progress/errors go to stderr. Multiple recipients return an array.

## How It Works

- Uses **Gmail API** via OAuth2 (not SMTP)
- Auth: `/home/ccuser/rateright-growth/scripts/campaign/gmail-auth.js`
- API wrapper: `/home/ccuser/rateright-growth/scripts/campaign/gmail-api.js`
- CLI tool: `/home/ccuser/rateright-growth/scripts/send-email.js`
- Authenticated as `admin@rateright.com.au`, sends as `michael@rateright.com.au`
- OAuth refresh token auto-renews — no manual token management needed

## Limits

- Gmail API: **~2,000 emails/day** (higher than SMTP's 500)
- Single email size: 25 MB (including attachments)
- DigitalOcean blocks SMTP ports (25/465/587) — all email MUST go through Gmail API

## Other Email Systems

| System | Used for | Config location |
|--------|----------|----------------|
| **Gmail API** (this SOP) | Bot emails, outreach, campaigns | `scripts/campaign/gmail-auth.js` |
| **Resend** | $50 app transactional emails (hire confirmations, notifications) | `/home/ccuser/the-50-dollar-app/.env.local` |
| **Gmail App Password** | Legacy/backup SMTP | `/root/.config/rateright-mail/credentials.json` |

## Troubleshooting

**"Token refresh failed"** — OAuth refresh token may have expired. Re-run the Gmail auth flow in `gmail-auth.js`. Google refresh tokens last indefinitely unless revoked, but can expire if unused for 6 months.

**"Send failed: 403"** — Gmail API quota exceeded or account suspended. Check https://console.cloud.google.com for quota status.

**"Send failed: 401"** — Access token expired and refresh failed. Check the refresh token is still valid.
