2026-03-03 10:20:07 -06:00
2026-03-03 10:20:07 -06:00
2026-03-03 10:20:07 -06:00
2026-03-03 10:20:07 -06:00
2026-03-03 10:20:07 -06:00
2026-03-03 10:20:07 -06:00
2026-03-03 10:20:07 -06:00
2026-03-03 10:20:07 -06:00

Email Signature Manager

A self-hosted, Dockerized Google Workspace email signature manager. Runs as a single container — designed for Unraid but works on any Docker host.

Features

  • Pulls user data automatically from Google Workspace Directory API
  • Renders per-user HTML signatures via Handlebars templates
  • Pushes signatures directly to Gmail via sendAs API (web + mobile)
  • Nightly batch push via configurable cron schedule
  • Web admin UI — live template editor with real-time preview
  • Single-user push for testing and onboarding
  • SQLite audit log of every push event
  • Basic auth protected UI
  • Zero external services — single container, no database server

Environment Variables

All secrets and configuration are passed as environment variables at runtime. No .env file is committed to this repo — see .env.example for all variable names and descriptions.

Variable Description Default
GOOGLE_ADMIN_EMAIL Workspace admin email for Directory API (required)
GOOGLE_CUSTOMER_ID Use my_customer for primary domain my_customer
SERVICE_ACCOUNT_KEY_PATH Path to sa.json inside container /app/secrets/sa.json
ADMIN_USERNAME Web UI login username (required)
ADMIN_PASSWORD Web UI login password (required)
PORT Internal app port 3000
CRON_SCHEDULE Cron expression for nightly push 0 2 * * *
NODE_ENV Node environment production

On Unraid

Set each variable directly in the Docker container template UI under the "Variables" section. No file needed on the host.

For Local Development

Copy .env.example to .env, fill in your values, then run:

docker-compose --env-file .env up -d --build

Google Workspace Setup (One-Time)

1. Create GCP Project & Enable APIs

  1. Go to https://console.cloud.google.com → New Project
  2. Enable Admin SDK API and Gmail API

2. Create Service Account

  1. APIs & Services → Credentials → Create Credentials → Service Account
  2. Name it email-sig-manager → Create
  3. Open the service account → Keys tab → Add Key → JSON
  4. Save the downloaded file as sa.json
  5. Place it at: secrets/sa.json on the Docker host (mounted as a volume, never in git)

3. Enable Domain-Wide Delegation

  1. Edit the service account → check Enable Google Workspace Domain-wide Delegation → Save
  2. Note the Client ID (long numeric string)

4. Authorize Scopes in Google Admin

  1. Go to https://admin.google.com
  2. Security → Access and data control → API controls → Manage Domain Wide Delegation
  3. Add new entry:
    • Client ID: (your service account client ID)
    • OAuth Scopes:
      https://www.googleapis.com/auth/admin.directory.user.readonly,https://www.googleapis.com/auth/gmail.settings.basic
      

Unraid Deployment

1. Clone the repo

cd /mnt/user/appdata
git clone https://github.com/YOURUSERNAME/email-sig-manager.git
cd email-sig-manager

2. Place the service account key

# Copy sa.json to the secrets folder (NOT tracked by git)
cp /path/to/sa.json secrets/sa.json
public/assets/logo.png

4. Add container in Unraid Docker UI

  • Repository: (or build from path)
  • Port: Map host port → 3000
  • Volumes:
    • /mnt/user/appdata/email-sig-manager/secrets/app/secrets
    • /mnt/user/appdata/email-sig-manager/data/app/data
    • /mnt/user/appdata/email-sig-manager/public/assets/app/public/assets
  • Variables: Add all variables from the table above

5. Build and start

docker-compose up -d --build

Or use the Unraid UI to start the container after configuring it.

Access the UI

http://UNRAID-IP:3000

First Run Checklist

  • secrets/sa.json is in place on the host
  • All environment variables are set in Unraid Docker UI
  • Logo placed at public/assets/logo.png
  • Open UI → Template Editor → preview looks correct
  • Push single user (yourself) to verify Gmail signature
  • Push to all users

Updating

cd /mnt/user/appdata/email-sig-manager
git pull
docker-compose up -d --build

secrets/, data/, and any host-managed files are gitignored and unaffected by pulls.


Project Structure

email-sig-manager/
├── src/
│   ├── index.js              # Express app entry
│   ├── routes/
│   │   ├── admin.js          # Template, logs, users API
│   │   └── push.js           # Signature push logic + batch runner
│   ├── services/
│   │   ├── googleAdmin.js    # Directory API — fetch all users
│   │   ├── gmailApi.js       # Gmail sendAs patch
│   │   ├── renderer.js       # Handlebars template renderer
│   │   └── scheduler.js      # node-cron nightly job
│   └── db/
│       ├── sqlite.js         # DB init and connection
│       └── audit.js          # Audit log read/write
├── templates/
│   └── default.hbs           # 2-column HTML signature template
├── public/
│   ├── dashboard.html        # Admin dashboard UI
│   ├── editor.html           # Template editor with live preview
│   └── assets/
│       └── logo.png          # Company logo (add your own)
├── secrets/                  # Gitignored — sa.json goes here
├── data/                     # Gitignored — SQLite DB lives here
├── Dockerfile
├── docker-compose.yml
├── package.json
└── .env.example              # Variable reference — safe to commit

Cron Schedule Reference

Expression Meaning
0 2 * * * 2:00 AM every day (default)
0 6 * * * 6:00 AM every day
0 2 * * 1 2:00 AM every Monday
0 2 1 * * 2:00 AM on the 1st of each month

Troubleshooting

Container won't start Run docker logs email-sig-manager — most likely a missing env variable or malformed sa.json.

"No primary sendAs" error The user may not have an active Gmail account, or domain-wide delegation scopes weren't saved correctly.

Signatures not showing on mobile Gmail iOS/Android automatically uses the web signature. Have the user force-close and reopen the app.

Template changes not saving Verify the container has write access to the templates/ directory. A .bak file is created on every save.


Security Notes

  • sa.json grants impersonation rights to every user in your domain — treat it like a master key
  • Never commit sa.json or a populated .env to GitHub
  • Change ADMIN_PASSWORD before first deployment
  • Consider placing the UI behind HTTPS if accessible outside your LAN
Description
No description provided
Readme 104 KiB
Languages
HTML 54.1%
JavaScript 41.9%
Handlebars 3.5%
Dockerfile 0.5%