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
sendAsAPI (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
- Go to https://console.cloud.google.com → New Project
- Enable Admin SDK API and Gmail API
2. Create Service Account
- APIs & Services → Credentials → Create Credentials → Service Account
- Name it
email-sig-manager→ Create - Open the service account → Keys tab → Add Key → JSON
- Save the downloaded file as
sa.json - Place it at:
secrets/sa.jsonon the Docker host (mounted as a volume, never in git)
3. Enable Domain-Wide Delegation
- Edit the service account → check Enable Google Workspace Domain-wide Delegation → Save
- Note the Client ID (long numeric string)
4. Authorize Scopes in Google Admin
- Go to https://admin.google.com
- Security → Access and data control → API controls → Manage Domain Wide Delegation
- 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
3. Add your company logo
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.jsonis 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.jsongrants impersonation rights to every user in your domain — treat it like a master key- Never commit
sa.jsonor a populated.envto GitHub - Change
ADMIN_PASSWORDbefore first deployment - Consider placing the UI behind HTTPS if accessible outside your LAN