How it works
Six things happen between an administrator publishing a template and a signature appearing at the bottom of somebody’s email.
The lifecycle of one signature
Section titled “The lifecycle of one signature”- A Microsoft 365 administrator grants admin consent to Sigil’s multi-tenant Entra application and deploys the Outlook add-in manifest through Integrated apps. This happens once.
- Someone starts a message. The add-in fires on
OnNewMessageCompose, which covers new messages, replies and forwards, and onOnMessageFromChangedwhen the sending account switches. No clicks, no task pane. - The add-in acquires an Entra access token silently, using MSAL nested app authentication (NAA) brokered by Outlook.
- The add-in calls the signature API. The API verifies the token, reads that person’s directory attributes from Microsoft Graph, and merges them into the template that applies to them. The result is Outlook-safe HTML with any images attached inline.
- The add-in applies it with
setSignatureAsync, attaches the inline images, and suppresses any locally configured signature so only one appears. It does not wait for steps 3 and 4 to start: the copy kept from that mailbox’s last message goes in first, and the fresh answer either matches it, replaces it or withdraws it when it arrives. - The add-in reports the outcome back to the API, which is what makes the Activity view possible.
The copy on the device
Section titled “The copy on the device”Steps 3 and 4 are where the time goes, and most of it is session warm-up rather than anything Sigil renders: brokering a token, loading the add-in, the first round trips. That cannot be made cheaper, but it can be taken off the path the person is waiting on, so the add-in starts from the last signature it served that mailbox and reconciles afterwards.
| What the fresh answer says | What happens to the message |
|---|---|
| The same signature | Nothing. No second set of attachments, no flicker |
| A different signature | The kept images come out and the new signature goes in |
| The mailbox is excluded, paused, or the subscription has lapsed | The kept copy is taken back out, leaving nothing in its place |
| No answer at all | The kept copy stands, and the message goes out with it |
The copy is held on the person’s own device for 45 days after that address last composed, renewed by every message. Where the device has no storage available to the add-in, there is no copy and the signature is simply fetched as before.
The trade is worth stating plainly, because it is the one thing an administrator will see: the first message somebody composes after a publish can show the old signature and then swap to the new one in front of them. What is sent is the new one, unless Sigil could not be reached at all, in which case the kept copy is what goes out and the table above says so. See why it sometimes changes as you watch.
What is checked at the API boundary
Section titled “What is checked at the API boundary”The add-in’s JavaScript is served from a public URL, so anything hidden inside it would be public too. There is no shared secret, and the security boundary is the token rather than anything embedded in the client.
Every signature request must carry a valid Entra access token. The server checks
the token’s cryptographic signature against the calling tenant’s published keys,
then its issuer, its audience, its home tenant claim (tid) and its delegated
scope, before returning anything.
The directory attributes in a signature (name, job title, phone number) are already visible to every colleague in the address book. The token requirement is what keeps them off the open internet. See the security model for the full picture.
How a template is chosen
Section titled “How a template is chosen”Sigil resolves three questions on every request: which template, which banner, and which footer.
The template comes from the assignment rules, evaluated in order, first match wins. A rule matches on a directory attribute being one of a set of values, or on membership of an Entra group, and names a template for new messages and a template for replies. Anyone that no rule matches gets the organisation-wide defaults.
The compose type decides which of the two roles is used. The add-in calls
getComposeTypeAsync, and a reply or forward asks for the reply signature. When
no reply template is configured, the new-message template is served instead.
The banner is whichever campaign window is currently open. The footer is the one matching the sending email domain, or the default if there is one.
Why changes are fast
Section titled “Why changes are fast”Rendered signatures are cached in Cloudflare KV, keyed by template id, template version, and the recipient’s email address. Publishing a template increments its version, which strands every cached entry for that template at once. The next request renders fresh.
That is why a template edit reaches users within seconds without an explicit purge. Banners and footers are part of the same cache key, so opening or closing a campaign window takes effect immediately.
A template that names the person sending, rather than only the mailbox, cannot be
cached per mailbox alone: the first person to send from sales@ would otherwise
hand their own name to everybody who sent from it next. Sigil detects that case
from the template itself, and from the compliance footer, and adds the sender to
the cache key for it. Templates that do not mention the sender keep the key they
had, so nothing here costs anything to an organisation not using the feature.
Assignment rules work the same way with a second cache in front of them. Evaluating a rule needs directory data, so the routing decision reached for each mailbox is cached too, keyed by a rules version that changes on every edit. Saving a rule list strands all of those at once, so a rules change also lands on the next compose. The ten minute freshness window on those entries exists for the change no version number can see, which is somebody moving department or joining a group in Entra. Past that window the decision is still used and the directory is re-read afterwards rather than mid-compose, so the change lands on the following message. Re-reading the directory while somebody waits is the slowest thing the serving path can do, and it would be paid by whoever happened to compose first.
The sending address, not the mailbox
Section titled “The sending address, not the mailbox”The add-in sends the address the message is actually being sent from, which is the Outlook From field. That may be a proxy or alias address rather than the mailbox’s primary one.
The signature follows the send. The {{email}} placeholder, the compliance
footer, and any emailDomain rule all reflect the sending address. One person
can carry a different brand’s address and template when sending from that
brand’s alias.
Two things keep that safe. A secondary alias that Graph cannot address directly
is resolved through a proxyAddresses directory filter, and the sending address
is printed only after it has been verified against the mailbox’s own
proxyAddresses. An unrecognised address falls back to the primary and can never
be injected into a signature.
Two identities, not one
Section titled “Two identities, not one”The compose request carries both the mailbox and the person. The From address says which mailbox the message leaves from, and the add-in’s token says who is signed in. On an ordinary send they name the same account. On a shared or delegated mailbox they do not, and that gap is what the sender placeholders render out of.
Sigil takes the person from the verified token rather than from anything the request asks for, so a signature cannot be made to claim somebody else wrote it. Sending from an alias of your own mailbox is not treated as a delegation, because the comparison is against every address the mailbox owns rather than against the one in the From field alone. See sending on behalf of a mailbox.
Multi-tenancy
Section titled “Multi-tenancy”Sigil is multi-tenant. Any organisation can connect and manage its own signatures against the same application registration and the same add-in manifest.
A tenant is an organisation, keyed by its Entra tenant id, which arrives on every verified token. All tenant data shares one database with a tenant id on every row, storage keys are prefixed by tenant, and cache keys are tenant-salted. The signature endpoint resolves the tenant from the token and refuses an unknown or suspended one.
There is nothing tenant-specific in the add-in. It uses the /organizations
authority, so NAA brokers each person’s token through their own tenant, whichever
that is.
What it runs on
Section titled “What it runs on”Sigil runs on Cloudflare’s edge network. Templates and metadata live in D1, inline images in R2, and rendered signatures in a KV cache. Billing runs on Stripe. Mail for invites, test emails and operator notices goes through Cloudflare Email Routing.
The practical consequence is that the signature path is edge-executed and close to the user wherever they are. See infrastructure.
