Google Workspaces - Přestaňte platit za centrální správu podpisů v Gmailu
Měli jsme správu e-mailových podpisů zdarma.
Byl to benefit od našeho tehdejšího distributora Google Workspace. Fungoval perfektně – všichni měli konzistentní, brandovaný podpis, nikdo nad tím nepřemýšlel.
Letos jsme přešli k jinému partnerovi – lepší podmínky, lepší podpora. Ale tento benefit jsme v balíčku nedostali.
Začal jsem se dívat, co stojí standalone SaaS alternativy:
Nástroj | Cena |
|---|---|
Exclaimer | $0.90 – $1.75 / uživatel / měsíc (Starter až Pro, roční billing) |
WiseStamp | od $1.90 / uživatel / měsíc |
BulkSignature | od $1.45 / uživatel / měsíc |
Při 25 lidech je to 600–1 200 Kč měsíčně za nástroj, jehož jedinou funkcí je nasadit HTML šablonu do Gmailu.
Řekl jsem si: to ne.
Otevřel jsem Claude, popsal co potřebuji – centrální správa podpisů přes Google Apps Script, service account, Domain-wide Delegation, automatický weekly trigger. Hodinu a půl ladění (hlavně jeden záludný OAuth detail, který většina návodů online vůbec nezmiňuje) – a bylo hotovo.
Tento článek je výsledek. Vše co potřebujete k tomu, abyste to zreplikovali.
Jak to funguje
Systém používá Google Apps Script se service accountem, který má Domain-wide Delegation (DWD). To umožňuje skriptu vystupovat jménem libovolného uživatele v doméně a nastavit mu podpis v Gmailu – bez individuálního přihlašování a bez jakéhokoliv zásahu ze strany zaměstnanců.
Apps Script → načte data uživatelů z Admin SDK (jméno, pozice, telefon, fotka) → přihlásí se jako každý uživatel přes service account + OAuth2 JWT → zavolá Gmail API a nastaví podpis → opakuje pro všechny aktivní uživatele → trigger se spouští automaticky každé pondělí v 8:00
Klíčový detail: Standardní Apps Script OAuth nemůže používat Domain-wide Delegation pro Gmail API. Musíte použít service account s JWT autentizací. Je to záměrné omezení ze strany Google a většina online návodů to vůbec nezmiňuje.
Co potřebujete
Google Workspace (jakýkoliv plán)
Přístup na Google Cloud Console (zdarma)
Role Super Admin v Google Workspace
Přibližně 30 minut na první nastavení
Část 1 – Google Cloud Console
1.1 Vytvoření projektu
Jděte na console.cloud.google.com
Klikněte na rozbalovací menu projektů vlevo nahoře → New Project
Název: company-signatures → Create
1.2 Zapnutí API
Levé menu → APIs & Services → Library
Vyhledejte Admin SDK API → Enable
Vyhledejte Gmail API → Enable
1.3 OAuth Consent Screen
Levé menu → APIs & Services → Credentials
Klikněte Configure consent screen (žlutý banner)
Vyberte Internal → Create
Vyplňte název aplikace, support e-mail, vývojářský kontakt → Save and Continue × 3
1.4 Vytvoření service accountu
Levé menu → IAM & Admin → Service Accounts
+ Create Service Account
Název: signatures-sa → Create and Continue
Přeskočte sekce Grant access → Done
1.5 Zjištění Client ID
Klikněte na nově vytvořený service account
Sjeďte dolů → rozbalte Advanced settings
V sekci Domain-wide Delegation je uvedeno Client ID – číslo si zkopírujte
ℹ️ Checkbox „Enable Domain-wide Delegation" Google z UI odstranil. DWD se aktivuje přímo v Workspace Admin zadáním Client ID (viz Část 2).
1.6 Stažení JSON klíče
Na stránce service accountu → záložka Keys
Add Key → Create new key → JSON → Create
Soubor se automaticky stáhne – uchovejte ho bezpečně, nikdy ho necommitujte do Gitu
⚠️ Tento JSON klíč umožňuje impersonaci kohokoliv ve vaší doméně. Uložte ho do password manageru a neposkytujte nikomu.
Část 2 – Google Workspace Admin
Tímto udělíte service accountu oprávnění vystupovat jménem všech uživatelů.
Jděte na admin.google.com
Navigujte na: Security → Access and data control → API controls
Domain wide delegation → Manage Domain Wide Delegation
Add new
Client ID: vložte číslo z kroku 1.5
OAuth Scopes – vložte přesně toto:
Authorize
ℹ️ Změna se projeví do 15 minut. Pokud dostanete chybu Delegation denied hned po nastavení, počkejte chvíli a zkuste znovu.
Část 3 – Apps Script
3.1 Vytvoření projektu
Jděte na script.google.com → New project
Přejmenujte na Company Signatures
3.2 Vložení kódu
Smažte výchozí obsah v Code.gs → vložte obsah souboru Code.gs
Klikněte + vedle Files → Script → pojmenujte Template
Vložte obsah souboru Template.gs
3.3 Přidání OAuth2 knihovny
Levé menu → + vedle Libraries
Vložte toto Script ID:
1B7FSrk5Zi6L1rSxxTDgDEUsPzlukDsi4KGuTMorsTQHhGBzBkMun4iDF
Look up → vyberte nejvyšší verzi → Identifier nechte jako OAuth2 → Add
3.4 Přidání Admin SDK
Levé menu → + vedle Services
Vyberte Admin SDK Directory API → Add
⚠️ Gmail API jako službu nepřidávejte – volá se přímo přes OAuth2 knihovnu.
3.5 Propojení s Cloud projektem
⚙️ Project Settings → Google Cloud Platform (GCP) Project
Change project → zadejte číslo projektu z Cloud Console → Set project
3.6 Uložení JSON klíče do Script Properties
JSON klíč je příliš dlouhý pro UI. Použijte tento workaround:
Vytvořte dočasný soubor Setup.gs ve vašem projektu
Vložte tento kód a nahraďte placeholder celým obsahem JSON souboru:
function saveJson() { const json = `VLOZ_SEM_CELY_OBSAH_JSON_SOUBORU`; PropertiesService.getScriptProperties() .setProperty('SERVICE_ACCOUNT_JSON', json); Logger.log('Uloženo!'); } Spusťte saveJson → ověřte, že log říká Uloženo!
Soubor Setup.gs ihned smažte – klíč nesmí zůstat viditelný v kódu
Část 4 – Spuštění a nasazení
Vždy nejdřív vyberte funkci z rozbalovacího menu v Apps Script editoru, pak klikněte Run.
Krok 1 – Otestujte na vlastním účtu
Funkce: step2_testOnlyMe → Run
Očekávaný výstup:
🧪 Testuju podpis pro: vas@vasadomena.cz ✓ vas@vasadomena.cz (Vaše Jméno) ✅ Hotovo! Zkontroluj podpis v Gmailu.
Zkontrolujte výsledek: Gmail → ⚙️ → Zobrazit všechna nastavení → Obecné → Podpis
Krok 2 – Nasazení všem
Funkce: step3_deployEveryone → Run
🚀 Nasazuji podpisy všem uživatelům domény... Nalezeno 23 aktivních uživatelů
✓ jana.novakova@firma.cz (Jana Nováková)
✓ petr.svoboda@firma.cz (Petr Svoboda) ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
✅ OK: 23 ❌ Chyby: 0 Celkem: 23
Krok 3 – Automatický weekly trigger
Levé menu → ⏰ Triggers → + Add Trigger
Nastavte: Function = step3_deployEveryone, Event source = Time-driven, Type = Week timer, Day = Monday, Time = 8am–9am
Save
Nový zaměstnanec dostane podpis automaticky nejbližší pondělí. Pro okamžité nasazení spusťte step3_deployEveryone ručně.
Část 5 – Úprava šablony podpisu
Upravte soubor Template.gs dle vašeho brandu. Funkce dostává tyto proměnné automaticky:
Proměnná | Zdroj |
|---|---|
name | Google Workspace profil – celé jméno |
title | Employee info – Job title |
Primární Gmail adresa | |
phone | Phone numbers – typ „Work" |
photo | URL profilové fotky (thumbnailPhotoUrl) |
icons.* | URL ikon z CONFIG.iconUrls |
CONFIG.address | Adresa firmy (stejná pro všechny) |
Web firmy (stejný pro všechny) |
ℹ️ Ikony se načítají jako externí URL (ne base64), aby HTML zůstalo pod limitem 10 000 znaků, který Gmail vyžaduje.
Po každé změně Template.gs spusťte step2_testOnlyMe pro kontrolu před nasazením všem.
Odkud se berou data zaměstnanců
Vše se tahá automaticky z Google Workspace:
Pole v podpisu | Kde to nastavit |
|---|---|
Jméno | Admin Console → Users → Name |
Pozice | Admin Console → Users → Employee info → Job title |
Telefon | Admin Console → Users → Phone numbers → typ „Work" |
Profilová fotka | Uživatel si nastaví sám na myaccount.google.com, nebo admin v Admin Console |
Pokud uživatel nemá vyplněný telefon, řádek s telefonem se v podpisu automaticky nezobrazí.
Řešení problémů
Chyba | Řešení |
|---|---|
SERVICE_ACCOUNT_JSON not set | JSON klíč nebyl uložen. Opakujte krok 3.6. |
Delegation denied | Počkejte 15 minut po nastavení DWD. Zkontrolujte Client ID. |
HTTP 400 – Signature exceeds 10,000 chars | Ikony musí být URL, ne base64. |
Fotka se nezobrazuje | Uživatel nemá profilovou fotku v Google Workspace. |
Service not enabled | Zapněte Admin SDK API v Cloud Console (krok 1.2). |
Cannot get token | DWD není správně nastaveno nebo špatné Client ID. |
Výsledek
Celkové náklady: 0 Kč / měsíc
Čas na nastavení: ~30 minut
Údržba: nulová – noví zaměstnanci dostávají podpisy automaticky
K vybudování tohoto řešení jsem využil Claude. Popsal jsem architekturu, společně jsme prošli OAuth záludností a celá věc byla hotová za odpoledne.
Použijte to, upravte si to, sdílejte to dál. Pokud to u vás funguje, rád to uslyším.
Část 6 – Kód: Code.gs
Co tento soubor dělá
Code.gs je mozek celého systému. Obsahuje:
CONFIG – jediné místo kde konfigurujete logo, ikony, adresu, web a sociální sítě
saveJson() – dočasná funkce pro uložení JSON klíče service accountu (spustí se jednou, pak smaže)
step2_testOnlyMe() – testování podpisu na vlastním účtu před ostrým nasazením
step3_deployEveryone() – nasazení podpisu všem uživatelům domény
Interní funkce pro OAuth2 autentizaci přes service account a sestavení HTML podpisu
Co upravit v CONFIG
Hodnota | Co změnit |
|---|---|
myEmail | Váš admin e-mail (pro testování) |
logoUrl | URL vašeho loga (PNG, veřejně dostupné) |
iconUrls.* | HEX barvu za posledním / v URL (např. 0078d4 = modrá) |
companyName | Název vaší firmy |
address | Adresa firmy |
website | URL webu firmy |
linkedinUrl | URL LinkedIn stránky firmy (nebo "" pro skrytí) |
youtubeUrl | URL YouTube kanálu (nebo "" pro skrytí) |
Ikony generuje signaturehound.com zdarma – stačí změnit hex barvu v URL.
Kód
Část 7 – Kód: Template.gs
Co tento soubor dělá
Template.gs obsahuje jedinou funkci buildSignatureHtml(), která přijme data uživatele a vrátí HTML podpisu jako string. Sem sáhněte pokud chcete změnit vzhled – layout, barvy, přidat/odebrat řádky.
Kód v Code.gs tuto funkci volá automaticky.
Nejčastější úpravy
Co chcete změnit | Kde v kódu |
|---|---|
Barvu oddělovacího pruhu | background-color:#000000 – nahraďte hex |
Barvu odkazu na web | color:#000000 – v sekci Web |
Velikost fotky | width="96" height="96" |
Velikost loga | width="124" |
Přidat Twitter/X | Zkopírovat blok youtubeIcon, přidat CONFIG.twitterUrl do CONFIG |
Po každé změně spusťte step2_testOnlyMe a zkontrolujte výsledek v Gmailu.
Kód
/**
* ╔══════════════════════════════════════════════════════════════╗
* ║ Šablona podpisu – Template.gs ║
* ╚══════════════════════════════════════════════════════════════╝
*
* TADY upravuješ vzhled podpisu. Po každé změně spusť
* step2_testOnlyMe v Code.gs a zkontroluj výsledek v Gmailu.
*
* Dostupné proměnné (doplní se automaticky z Workspace profilu):
* name – celé jméno uživatele
* title – pracovní pozice (Employee info → Job title)
* email – primární e-mailová adresa
* phone – pracovní telefon, prázdný string pokud není vyplněn
* photo – URL profilové fotky, null pokud uživatel nemá fotku
*
* Dostupné objekty z Code.gs:
* icons.logo – logo firmy
* icons.email – ikona e-mailu
* icons.phone – ikona telefonu
* icons.location – ikona adresy
* icons.web – ikona webu
* icons.linkedin – ikona LinkedInu
* icons.youtube – ikona YouTube
* CONFIG.address – adresa firmy
* CONFIG.website – web firmy
* CONFIG.companyName – název firmy
* CONFIG.linkedinUrl – URL LinkedIn profilu firmy
* CONFIG.youtubeUrl – URL YouTube kanálu firmy
*
* DŮLEŽITÉ LIMITY:
* Gmail má limit 10 000 znaků na podpis.
* Ikony musí být načítány jako URL (ne base64) – jinak limit překročíš.
* Vyhni se externím fontům (Google Fonts) – Gmail je ignoruje.
* Bezpečné fonty: Arial, Helvetica, Verdana, Georgia, Times New Roman
*/
function buildSignatureHtml(name, title, email, phone, photo, icons) {
// ── FOTKA ──────────────────────────────────────────────────────
// Zobrazíme profilovou fotku jako kruh, nebo šedý placeholder pokud není
var photoCell = photo
? '<img src="' + photo + '" width="96" height="96" style="border-radius:50%;width:96px;height:96px;object-fit:cover;display:block;margin:0 auto;" alt="' + name + '">'
: '<div style="width:96px;height:96px;border-radius:50%;background:#e8e8e8;margin:0 auto;"></div>';
// ── TELEFON ────────────────────────────────────────────────────
// Řádek s telefonem zobrazíme jen pokud uživatel telefon vyplněný má
var phoneRow = phone
? '<tr><td style="padding:2px 8px 2px 0;vertical-align:middle;"><img src="' + icons.phone + '" width="14" height="14" style="display:block;"></td><td style="font-size:12px;color:#888888;padding:2px 0;vertical-align:middle;">' + phone + '</td></tr>'
: "";
// ── SOCIÁLNÍ SÍTĚ ──────────────────────────────────────────────
// Zobrazíme jen ikony pro sítě s vyplněnou URL (prázdné CONFIG hodnoty = nezobrazovat)
var linkedinIcon = CONFIG.linkedinUrl
? '<td style="padding-right:6px;"><a href="' + CONFIG.linkedinUrl + '" style="text-decoration:none;"><img src="' + icons.linkedin + '" width="26" height="26" alt="LinkedIn" style="display:block;"></a></td>'
: "";
var youtubeIcon = CONFIG.youtubeUrl
? '<td><a href="' + CONFIG.youtubeUrl + '" style="text-decoration:none;"><img src="' + icons.youtube + '" width="26" height="26" alt="YouTube" style="display:block;"></a></td>'
: "";
// ── HLAVNÍ HTML TABULKA ────────────────────────────────────────
// Používáme HTML tabulku místo CSS flexbox/grid – jen tabulky jsou
// spolehlivě zobrazeny ve všech e-mailových klientech.
var html = [];
html.push('<table cellpadding="0" cellspacing="0" border="0" style="font-family:Arial,Helvetica,sans-serif;font-size:12px;color:#888888;max-width:540px;">');
html.push('<tr>');
// Levý sloupec: fotka + logo
html.push('<td style="vertical-align:top;padding-right:18px;width:130px;text-align:center;">');
html.push('<table cellpadding="0" cellspacing="0" style="width:130px;">');
html.push('<tr><td style="padding-bottom:10px;text-align:center;">' + photoCell + '</td></tr>');
html.push('<tr><td style="text-align:center;"><img src="' + icons.logo + '" width="124" height="auto" alt="' + CONFIG.companyName + '" style="display:block;margin:0 auto;max-width:124px;"></td></tr>');
html.push('</table></td>');
// Oddělovač – změň #000000 na barvu svého brandu
html.push('<td style="width:1px;background-color:#000000;padding:0;"> </td>');
// Pravý sloupec
html.push('<td style="vertical-align:top;padding-left:18px;">');
// Jméno, pozice, firma
html.push('<table cellpadding="0" cellspacing="0">');
html.push('<tr><td style="font-size:15px;font-weight:bold;color:#1a1a1a;font-family:Arial,Helvetica,sans-serif;line-height:1.3;padding-bottom:1px;">' + name + '</td></tr>');
html.push('<tr><td style="font-size:12px;color:#888888;padding-bottom:1px;">' + title + '</td></tr>');
html.push('<tr><td style="font-size:12px;color:#888888;padding-bottom:10px;">' + CONFIG.companyName + '</td></tr>');
html.push('</table>');
// Kontaktní údaje
html.push('<table cellpadding="0" cellspacing="0" style="margin-bottom:8px;">');
// E-mail
html.push('<tr>');
html.push('<td style="padding:2px 8px 2px 0;vertical-align:middle;"><img src="' + icons.email + '" width="14" height="14" style="display:block;"></td>');
html.push('<td style="font-size:12px;color:#888888;padding:2px 0;vertical-align:middle;"><a href="mailto:' + email + '" style="color:#888888;text-decoration:none;">' + email + '</a></td>');
html.push('</tr>');
// Telefon (prázdný pokud nevyplněn)
html.push(phoneRow);
// Adresa
html.push('<tr>');
html.push('<td style="padding:2px 8px 2px 0;vertical-align:middle;"><img src="' + icons.location + '" width="14" height="14" style="display:block;"></td>');
html.push('<td style="font-size:12px;color:#888888;padding:2px 0;vertical-align:middle;">' + CONFIG.address + '</td>');
html.push('</tr>');
// Web – změň barvu (#000000) na barvu svého brandu
html.push('<tr>');
html.push('<td style="padding:2px 8px 2px 0;vertical-align:middle;"><img src="' + icons.web + '" width="14" height="14" style="display:block;"></td>');
html.push('<td style="font-size:12px;padding:2px 0;vertical-align:middle;"><a href="' + CONFIG.website + '" style="color:#000000;font-weight:bold;text-decoration:none;">' + CONFIG.website.replace("https://", "").replace("http://", "") + '</a></td>');
html.push('</tr>');
html.push('</table>');
// Sociální sítě
html.push('<table cellpadding="0" cellspacing="0"><tr>' + linkedinIcon + youtubeIcon + '</tr></table>');
html.push('</td></tr></table>');
return html.join("\n");
}

