Add files via upload
This commit is contained in:
304
README.md
304
README.md
@@ -17,14 +17,27 @@ Runs as a single container — designed for Unraid but works on any Docker host.
|
||||
|
||||
---
|
||||
|
||||
## Logo & Image Hosting
|
||||
|
||||
All images referenced in the signature template must be publicly accessible via HTTPS.
|
||||
The default logo URL is:
|
||||
```
|
||||
https://alwisp.com/uploads/logo.png
|
||||
```
|
||||
Upload your logo and any other signature images to `https://alwisp.com/uploads/` and
|
||||
reference them by full URL in the template. The logo URL can also be changed live
|
||||
in the Template Editor UI without rebuilding the container.
|
||||
|
||||
---
|
||||
|
||||
## 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.
|
||||
No `.env` file is committed to this repo — see `.env.example` for all variable names.
|
||||
|
||||
| Variable | Description | Default |
|
||||
|---|---|---|
|
||||
| `GOOGLE_ADMIN_EMAIL` | Workspace admin email for Directory API | *(required)* |
|
||||
| `GOOGLE_ADMIN_EMAIL` | Workspace admin email (e.g. jason@messagepoint.tv) | *(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)* |
|
||||
@@ -34,12 +47,12 @@ No `.env` file is committed to this repo — see `.env.example` for all variable
|
||||
| `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.
|
||||
Set each variable directly in the **Docker container template UI** under Variables.
|
||||
|
||||
### For Local Development
|
||||
Copy `.env.example` to `.env`, fill in your values, then run:
|
||||
```bash
|
||||
cp .env.example .env
|
||||
# fill in values
|
||||
docker-compose --env-file .env up -d --build
|
||||
```
|
||||
|
||||
@@ -47,192 +60,126 @@ docker-compose --env-file .env up -d --build
|
||||
|
||||
## Part 1 — Google Cloud Console Setup
|
||||
|
||||
This section walks through creating the service account and downloading the key
|
||||
that allows the app to impersonate users in your Google Workspace domain.
|
||||
|
||||
### Step 1 — Create a Google Cloud Project
|
||||
|
||||
1. Open https://console.cloud.google.com and sign in with your Google Workspace admin account
|
||||
2. Click the **project dropdown** in the top navigation bar (next to the Google Cloud logo)
|
||||
3. Click **New Project** in the top right of the dialog
|
||||
4. Enter a project name: `email-sig-manager`
|
||||
5. Leave the organization as your Workspace domain → click **Create**
|
||||
6. Wait a few seconds, then select the new project from the dropdown to make it active
|
||||
|
||||
> **Note:** If your org already has a GCP project you prefer to use, you can skip
|
||||
> project creation and just enable the APIs inside the existing project.
|
||||
|
||||
---
|
||||
1. Open https://console.cloud.google.com — sign in with your Google Workspace admin account
|
||||
2. Click the **project dropdown** (top nav bar) → **New Project**
|
||||
3. Name: `email-sig-manager` → **Create**
|
||||
4. Select the new project from the dropdown to make it active
|
||||
|
||||
### Step 2 — Enable Required APIs
|
||||
|
||||
The app needs two Google APIs enabled in your project.
|
||||
**Admin SDK API:**
|
||||
1. Go to **APIs & Services → Library**
|
||||
2. Search `Admin SDK API` → click result → **Enable**
|
||||
|
||||
**Enable Admin SDK API:**
|
||||
1. In the GCP Console, go to **APIs & Services → Library** (left sidebar)
|
||||
2. Search for `Admin SDK API`
|
||||
3. Click the result → click **Enable**
|
||||
|
||||
**Enable Gmail API:**
|
||||
**Gmail API:**
|
||||
1. Go back to **APIs & Services → Library**
|
||||
2. Search for `Gmail API`
|
||||
3. Click the result → click **Enable**
|
||||
|
||||
Both should now show as **Enabled** under **APIs & Services → Enabled APIs & Services**.
|
||||
|
||||
---
|
||||
2. Search `Gmail API` → click result → **Enable**
|
||||
|
||||
### Step 3 — Create the Service Account
|
||||
|
||||
1. In the left sidebar, go to **IAM & Admin → Service Accounts**
|
||||
2. Click **+ Create Service Account** at the top
|
||||
3. Fill in the details:
|
||||
- **Service account name:** `email-sig-manager`
|
||||
- **Service account ID:** will auto-fill as `email-sig-manager`
|
||||
- **Description:** `Email signature push service for Google Workspace`
|
||||
4. Click **Create and Continue**
|
||||
5. On the "Grant this service account access to project" step — **skip this, click Continue**
|
||||
6. On the "Grant users access" step — **skip this too, click Done**
|
||||
1. Go to **IAM & Admin → Service Accounts**
|
||||
2. Click **+ Create Service Account**
|
||||
3. Name: `email-sig-manager` → **Create and Continue**
|
||||
4. Skip role assignment → **Continue** → skip user access → **Done**
|
||||
|
||||
You will land back on the service accounts list and see your new account listed.
|
||||
### Step 4 — Enable Domain-Wide Delegation
|
||||
|
||||
---
|
||||
|
||||
### Step 4 — Enable Domain-Wide Delegation on the Service Account
|
||||
|
||||
1. Click the service account name (`email-sig-manager`) in the list to open it
|
||||
2. Click the **Edit** button (pencil icon) at the top
|
||||
3. Scroll down to find **"Show advanced settings"** — click it to expand
|
||||
4. Check the box for **"Enable Google Workspace Domain-wide Delegation"**
|
||||
5. Enter a product name for the consent screen if prompted (e.g., `Email Signature Manager`)
|
||||
1. Click the service account name to open it
|
||||
2. Click **Edit** (pencil icon)
|
||||
3. Expand **Show advanced settings**
|
||||
4. Check **Enable Google Workspace Domain-wide Delegation**
|
||||
5. Enter product name: `Email Signature Manager`
|
||||
6. Click **Save**
|
||||
7. Back on the service account detail page, note the **Client ID** (long number) — copy it
|
||||
|
||||
After saving, return to the service account detail page. You should now see a
|
||||
**"Domain-wide delegation"** line showing a **Client ID** (a long numeric string,
|
||||
e.g., `112233445566778899`). **Copy this Client ID** — you will need it in Part 2.
|
||||
### Step 5 — Download the JSON Key
|
||||
|
||||
---
|
||||
|
||||
### Step 5 — Download the Service Account JSON Key
|
||||
|
||||
1. On the service account detail page, click the **Keys** tab
|
||||
2. Click **Add Key → Create New Key**
|
||||
3. Select **JSON** as the key type → click **Create**
|
||||
4. The key file downloads automatically to your computer
|
||||
5. **Rename the file to `sa.json`**
|
||||
6. Store it securely — this file grants impersonation access to all users in your domain
|
||||
|
||||
> This file goes in the `secrets/` folder on your Unraid host. It is gitignored
|
||||
> and must never be committed to GitHub.
|
||||
1. Click the **Keys** tab on the service account
|
||||
2. **Add Key → Create New Key → JSON → Create**
|
||||
3. Rename the downloaded file to `sa.json`
|
||||
4. Place it at `secrets/sa.json` on your Unraid host — never commit to GitHub
|
||||
|
||||
---
|
||||
|
||||
## Part 2 — Google Admin Console Authorization
|
||||
|
||||
This section delegates authority to the service account inside Google Admin,
|
||||
allowing it to impersonate users and update their Gmail signatures.
|
||||
|
||||
### Step 6 — Authorize the Service Account in Google Admin
|
||||
|
||||
1. Open a new tab and go to https://admin.google.com
|
||||
2. Sign in with your **Google Workspace super admin** account
|
||||
3. In the left sidebar, navigate to:
|
||||
**Security → Access and data control → API controls**
|
||||
4. On the API controls page, click **Manage Domain Wide Delegation**
|
||||
5. Click **Add new** to add a new authorized client
|
||||
|
||||
Fill in the form:
|
||||
- **Client ID:** Paste the numeric Client ID you copied in Step 4
|
||||
(find it again at GCP Console → IAM & Admin → Service Accounts → your account → Details)
|
||||
- **OAuth Scopes:** Paste the following exactly, as one comma-separated line:
|
||||
```
|
||||
https://www.googleapis.com/auth/admin.directory.user.readonly,https://www.googleapis.com/auth/gmail.settings.basic
|
||||
```
|
||||
### Step 6 — Authorize Domain-Wide Delegation
|
||||
|
||||
1. Go to https://admin.google.com — sign in as super admin
|
||||
2. Navigate to: **Security → Access and data control → API controls**
|
||||
3. Click **Manage Domain Wide Delegation**
|
||||
4. Click **Add new**
|
||||
5. Fill in:
|
||||
- **Client ID:** *(paste the number from Step 4)*
|
||||
- **OAuth Scopes:**
|
||||
```
|
||||
https://www.googleapis.com/auth/admin.directory.user.readonly,https://www.googleapis.com/auth/gmail.settings.basic
|
||||
```
|
||||
6. Click **Authorize**
|
||||
|
||||
> If you receive an error saying "client ID not found", wait 2–3 minutes after
|
||||
> enabling domain-wide delegation in Step 4 and try again — GCP propagation
|
||||
> can take a moment.
|
||||
> If you get "client ID not found" — wait 2–3 minutes after Step 4 and try again.
|
||||
|
||||
---
|
||||
### Step 7 — Verify
|
||||
|
||||
### Step 7 — Verify the Authorization
|
||||
|
||||
1. After clicking Authorize you should see the new entry in the list
|
||||
2. Click **View details** next to your entry
|
||||
3. Confirm both scopes are listed:
|
||||
- `https://www.googleapis.com/auth/admin.directory.user.readonly`
|
||||
- `https://www.googleapis.com/auth/gmail.settings.basic`
|
||||
4. If a scope is missing, click **Edit**, re-enter the full comma-separated scope string, and click **Authorize** again
|
||||
|
||||
> **Multi-party approval note:** If your Google Workspace org has multi-party
|
||||
> approval enabled for admin actions, another super admin will need to approve
|
||||
> this delegation before it takes effect.
|
||||
1. Click **View details** next to your new entry
|
||||
2. Confirm both scopes are listed
|
||||
3. If a scope is missing, click Edit, re-enter the full scope string, and re-authorize
|
||||
|
||||
---
|
||||
|
||||
## Part 3 — Unraid Deployment
|
||||
|
||||
### Step 8 — Clone the Repository
|
||||
|
||||
SSH into your Unraid server or use the Unraid terminal:
|
||||
### Step 8 — Clone the Repo
|
||||
|
||||
```bash
|
||||
cd /mnt/user/appdata
|
||||
git clone https://github.com/YOURUSERNAME/email-sig-manager.git
|
||||
cd email-sig-manager
|
||||
git clone https://github.com/YOURUSERNAME/email-sig-manager.git email-sigs
|
||||
cd email-sigs
|
||||
```
|
||||
|
||||
### Step 9 — Place the Service Account Key
|
||||
|
||||
Copy `sa.json` (downloaded in Step 5) into the `secrets/` folder:
|
||||
|
||||
```bash
|
||||
# From your PC to Unraid (run this on your PC):
|
||||
scp sa.json root@UNRAID-IP:/mnt/user/appdata/email-sig-manager/secrets/sa.json
|
||||
# From your PC (run on your PC):
|
||||
scp sa.json root@UNRAID-IP:/mnt/user/appdata/email-sigs/secrets/sa.json
|
||||
```
|
||||
Or copy via SMB: `\\UNRAID-IP\appdata\email-sigs\secrets\`
|
||||
|
||||
### Step 10 — Upload Logo
|
||||
|
||||
Upload your logo to `https://alwisp.com/uploads/logo.png` via your web server.
|
||||
The template references this URL directly — no local file needed.
|
||||
|
||||
### Step 11 — Build the Docker Image
|
||||
|
||||
SSH into Unraid and run:
|
||||
```bash
|
||||
cd /mnt/user/appdata/email-sigs
|
||||
docker build -t email-sigs:latest .
|
||||
```
|
||||
|
||||
Or copy it via your Unraid SMB share using Windows Explorer:
|
||||
```
|
||||
\\UNRAID-IP\appdata\email-sig-manager\secrets\
|
||||
```
|
||||
### Step 12 — Configure Container in Unraid Docker UI
|
||||
|
||||
### Step 10 — Add Your Company Logo
|
||||
- **Name:** `email-sigs`
|
||||
- **Repository:** `email-sigs` *(local image built in Step 11)*
|
||||
|
||||
Place your logo file at:
|
||||
```
|
||||
/mnt/user/appdata/email-sig-manager/public/assets/logo.png
|
||||
```
|
||||
Recommended: PNG, transparent background, 160×160px or smaller.
|
||||
**Volume mappings:**
|
||||
|
||||
### Step 11 — Configure Container in Unraid Docker UI
|
||||
|
||||
1. In the Unraid web UI, go to **Docker → Add Container**
|
||||
2. Set the following:
|
||||
- **Name:** `email-sig-manager`
|
||||
- **Repository:** *(leave blank if building locally — use the path method below)*
|
||||
- **Network Type:** Bridge
|
||||
|
||||
**Add these Volume mappings:**
|
||||
|
||||
| Container Path | Host Path |
|
||||
| Host Path | Container Path |
|
||||
|---|---|
|
||||
| `/app/secrets` | `/mnt/user/appdata/email-sig-manager/secrets` |
|
||||
| `/app/data` | `/mnt/user/appdata/email-sig-manager/data` |
|
||||
| `/app/public/assets` | `/mnt/user/appdata/email-sig-manager/public/assets` |
|
||||
| `/mnt/user/appdata/email-sigs/secrets` | `/app/secrets` |
|
||||
| `/mnt/user/appdata/email-sigs/data` | `/app/data` |
|
||||
| `/mnt/user/appdata/email-sigs/public/assets` | `/app/public/assets` |
|
||||
|
||||
**Add these Port mapping:**
|
||||
**Port mapping:** Host `3000` → Container `3000`
|
||||
|
||||
| Container Port | Host Port |
|
||||
|---|---|
|
||||
| `3000` | `3000` *(or any open port)* |
|
||||
|
||||
**Add these Variables** (click Add Variable for each):
|
||||
**Variables:**
|
||||
|
||||
| Name | Value |
|
||||
|---|---|
|
||||
| `GOOGLE_ADMIN_EMAIL` | `admin@messagepointmedia.com` |
|
||||
| `GOOGLE_ADMIN_EMAIL` | `jason@messagepoint.tv` |
|
||||
| `GOOGLE_CUSTOMER_ID` | `my_customer` |
|
||||
| `SERVICE_ACCOUNT_KEY_PATH` | `/app/secrets/sa.json` |
|
||||
| `ADMIN_USERNAME` | `admin` |
|
||||
@@ -241,57 +188,39 @@ Recommended: PNG, transparent background, 160×160px or smaller.
|
||||
| `CRON_SCHEDULE` | `0 2 * * *` |
|
||||
| `NODE_ENV` | `production` |
|
||||
|
||||
### Step 12 — Build and Start
|
||||
|
||||
```bash
|
||||
cd /mnt/user/appdata/email-sig-manager
|
||||
docker-compose up -d --build
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Part 4 — First Run & Verification
|
||||
|
||||
### Step 13 — Access the Admin UI
|
||||
### Step 13 — Access the UI
|
||||
|
||||
Open a browser and navigate to:
|
||||
```
|
||||
http://UNRAID-IP:3000
|
||||
```
|
||||
Log in with your `ADMIN_USERNAME` and `ADMIN_PASSWORD`.
|
||||
|
||||
### Step 14 — Test with a Single User First
|
||||
### Step 14 — Preview and Test
|
||||
|
||||
1. Go to the **Template Editor** page
|
||||
2. Verify the live preview renders correctly with your info
|
||||
3. Make any template adjustments needed
|
||||
4. Return to the **Dashboard**
|
||||
5. In the **Push Single User** field, enter your own email address
|
||||
6. Click **Push Single User**
|
||||
7. Open Gmail in a new tab → compose a new email → verify the signature appears correctly
|
||||
8. Check the Gmail mobile app as well (force-close and reopen if needed)
|
||||
1. Go to **Template Editor** — verify the preview renders correctly
|
||||
2. Back on **Dashboard** → enter your own email → **Push Single User**
|
||||
3. Open Gmail → compose a new message → verify signature appears
|
||||
4. Check Gmail mobile app (force-close and reopen if needed)
|
||||
|
||||
### Step 15 — Push to All Users
|
||||
|
||||
Once you've verified your own signature looks correct:
|
||||
|
||||
1. Click **Push to All Users** on the Dashboard
|
||||
2. Confirm the dialog
|
||||
3. Watch the audit log populate with success/error statuses
|
||||
4. The nightly cron will take over automatically from here
|
||||
Once verified, click **Push to All Users** on the Dashboard.
|
||||
The nightly cron will keep all signatures in sync automatically.
|
||||
|
||||
---
|
||||
|
||||
## Updating the Project
|
||||
## Updating
|
||||
|
||||
```bash
|
||||
cd /mnt/user/appdata/email-sig-manager
|
||||
cd /mnt/user/appdata/email-sigs
|
||||
git pull
|
||||
docker-compose up -d --build
|
||||
docker build -t email-sigs:latest .
|
||||
docker restart email-sigs
|
||||
```
|
||||
|
||||
`secrets/`, `data/`, and host-managed files are gitignored and unaffected by pulls.
|
||||
|
||||
---
|
||||
|
||||
## Project Structure
|
||||
@@ -299,7 +228,7 @@ docker-compose up -d --build
|
||||
```
|
||||
email-sig-manager/
|
||||
├── src/
|
||||
│ ├── index.js # Express app entry
|
||||
│ ├── index.js # Express app (no dotenv — vars injected by Docker)
|
||||
│ ├── routes/
|
||||
│ │ ├── admin.js # Template, logs, users API
|
||||
│ │ └── push.js # Signature push logic + batch runner
|
||||
@@ -316,11 +245,10 @@ email-sig-manager/
|
||||
├── public/
|
||||
│ ├── dashboard.html # Admin dashboard UI
|
||||
│ ├── editor.html # Template editor with live preview
|
||||
│ └── assets/
|
||||
│ └── logo.png # Company logo (add your own)
|
||||
│ └── assets/ # Local asset dir (optional, logo served remotely)
|
||||
├── secrets/ # Gitignored — sa.json goes here
|
||||
├── data/ # Gitignored — SQLite DB lives here
|
||||
├── Dockerfile
|
||||
├── Dockerfile # Uses npm install (not npm ci)
|
||||
├── docker-compose.yml
|
||||
├── package.json
|
||||
└── .env.example # Variable reference — safe to commit
|
||||
@@ -341,29 +269,33 @@ email-sig-manager/
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
**"Cannot find module" errors on startup**
|
||||
Rebuild the image: `docker build -t email-sigs:latest .` then restart.
|
||||
|
||||
**Container won't start**
|
||||
Run `docker logs email-sig-manager`. Most likely a missing env variable or malformed `sa.json`.
|
||||
Run `docker logs email-sigs` — 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 were not saved correctly in Google Admin.
|
||||
The user may not have an active Gmail account, or domain-wide delegation scopes were not saved correctly.
|
||||
|
||||
**"Client ID not found" when authorizing in Google Admin**
|
||||
Wait 2–3 minutes after enabling domain-wide delegation in GCP and try again.
|
||||
**"Client ID not found" in Google Admin**
|
||||
Wait 2–3 minutes after enabling domain-wide delegation in GCP, then try again.
|
||||
|
||||
**Signatures not showing on mobile**
|
||||
Gmail iOS/Android automatically uses the web signature. Have the user force-close and reopen the Gmail app after the push.
|
||||
Gmail iOS/Android uses the web signature automatically. 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.
|
||||
Verify the container has write access to `templates/`. A `.bak` file is created on every save.
|
||||
|
||||
**401 / permission denied errors in logs**
|
||||
The OAuth scopes in Google Admin may not have saved correctly. Go back to Admin Console → Security → API Controls → Domain Wide Delegation → View Details and verify both scopes are listed.
|
||||
**401 / permission denied errors**
|
||||
Go to Google Admin → Security → API Controls → Domain Wide Delegation → View Details
|
||||
and verify both OAuth scopes are listed correctly.
|
||||
|
||||
---
|
||||
|
||||
## 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
|
||||
- Never commit `sa.json` to GitHub — it is gitignored
|
||||
- Change `ADMIN_PASSWORD` before first deployment
|
||||
- Consider placing the UI behind HTTPS if accessible outside your LAN
|
||||
- Consider HTTPS via a reverse proxy if the UI is accessible outside your LAN
|
||||
|
||||
Reference in New Issue
Block a user