SignetMail docs Open portal →

#Configuration reference

The server reads standard ASP.NET Core configuration: appsettings.json, then environment variables (the way the Docker setup does it). In environment variables, a nested key uses a double underscore: SignetMail:Portal:ClientId becomes SignetMail__Portal__ClientId.

In the cloud setup you normally touch only .env; docker-compose.yml maps it to the settings below.

#.env (cloud deployment)

Variable Required Description
SIGNETMAIL_VERSION no Image tag, default latest.
SIGNETMAIL_HOST yes Public host name.
ENTRA_TENANT_ID yes Entra directory (tenant) ID.
ENTRA_CLIENT_ID yes App registration (client) ID.
PORTAL_OWNER yes UPN of the first Owner.
GRAPH_CERT_PASSWORD yes Password of certs/graph.pfx.
PORTAL_ALLOWED_IPS no Space-separated IPs/CIDRs allowed to reach /portal/* and /api/portal/*. Default: everyone.
BACKUP_GIT_REMOTE no SSH URL for encrypted backups.

Warning. .env contains secrets. Keep it readable by the admin only (chmod 600 .env) and never commit it.

#Application settings

#Authentication — AzureAd

Key Description
Instance https://login.microsoftonline.com/
TenantId Tenant ID.
ClientId App registration ID.
Audience Optional; set it only if you use a non-default Application ID URI.

#General — SignetMail

Key Default Description
PublicUrl from request Public base address, for example https://app.example.com. Used in the add-in manifest, /portal/config.json and campaign links. Behind a proxy also set ASPNETCORE_FORWARDEDHEADERS_ENABLED=true.
EnableDevelopmentAuth false Allows sign-in by header. Works only in the Development environment; never enable on a public server.
CorsOrigins [] Origins allowed to call the API from a browser. Empty = CORS off (the hosted add-in and portal are same-origin and need nothing).
TemplatesPath templates Folder with initial templates used to seed an empty database.
DefaultTemplate default Identifier of the fallback signature.

#Directory — SignetMail:Directory

Key Default Description
Source Sample Graph (Entra ID) or Google (Google Workspace) in production; Sample reads a JSON file for development.
SyncIntervalMinutes 60 How often the directory is re-read.
SampleFile sample-users.json Development data.

#Microsoft Graph — SignetMail:Graph

Key Description
TenantId, ClientId Same app registration as sign-in.
CertificatePath Path to the .pfx (in the container: /certs/graph.pfx).
CertificatePassword Password of the .pfx.
CertificateThumbprint Alternative on Windows: use a certificate from the My store.

#Google Workspace — SignetMail:Google

Used when Directory:Source is Google. See Google Workspace.

Key Default Description
ServiceAccountKeyFile Path to the service account JSON key (in the container: /google/service-account.json).
ServiceAccountKeyJson The key's content instead of a file (for secret stores).
AdminEmail Super admin the service account acts as when reading the directory.
ClientId OAuth Client ID for Google sign-in to the portal. Empty = Google sign-in off.
AllowedDomains Domains whose accounts may sign in (required when ClientId is set).
PushSignatures false Automatically write signatures into Gmail.
PushIntervalMinutes 60 How often to check for changed signatures (minimum 5).

#Portal — SignetMail:Portal

Key Description
Owners List of UPNs that are Owners on every start.
ClientId, TenantId Handed to the browser through /portal/config.json.
ApiScope api://<ClientId>/access_as_user.
RootOrganizationSlug Slug of the root organization created on first start (default default).
UploadsPath Where uploaded images are stored (default data/uploads).

#Database — SignetMail:Database

Key Default Description
Provider Sqlite Sqlite or Postgres.
ConnectionString Data Source=data/signetmail.db Connection string for the chosen provider.

SQLite is perfectly adequate for a single server. Choose PostgreSQL when you want managed backups or run several instances.

Note. The schema is created automatically on first start. There are no automatic migrations yet: after an update that changes the data model, release notes will say what to do. Always take a backup before updating.

#Security limits — SignetMail:Security

Key Default Description
RateLimitPerMinute 600 Requests per minute per client address for the whole API.
AnonymousRateLimitPerMinute 120 Stricter limit for public paths (/c/…, /uploads/…). Exceeding either returns HTTP 429.

#License — SignetMail:License

Key Description
Key Optional license key (see Licensing). A key applied in the portal takes precedence and is stored in the database.
PublicKey Optional override of the vendor's public key used to verify license keys. Leave empty to use the built-in key.

#Seeding settings (first start only)

Organization, Organizations and Rules in appsettings.json fill an empty database on the very first start and are ignored afterwards; after that, everything is managed in the portal. A fresh production install starts with one organization, My company.

#Endpoints at a glance

Path Purpose Access
/portal/ Administration portal Entra sign-in; optionally IP-restricted
/docs/ This documentation Public, static
/addin/manifest.xml, /addin/… Outlook add-in Public (Microsoft downloads it)
/api/v1/signature Signature for the signed-in user Entra token (add-in) or Kerberos (agent)
/api/portal/… Portal API Entra token + role
/c/<id> Campaign click redirect Public
/uploads/<hash>.png Uploaded logos and banners Public (recipients load them)
/health {status, lastSyncUtc} Public, no sensitive data
SignetMail documentation · version main