Open Pryv.io email configuration
Open Pryv.io sends two kinds of transactional email: the welcome message after account creation and the password-reset message after a reset request. Both are optional (disabled independently via services.email.enabled.*) and both share the same SMTP transport + Pug template pipeline.
v2 supports two delivery paths. Pick one at services.email.method in override-config.yml:
method |
Runs | Templates live in | Use when |
|---|---|---|---|
in-process (recommended) |
The api-server worker that handled registration / reset-password | PlatformDB (rqlite, cluster-wide) | Single- and multi-core v2 deployments. No extra process, one less localhost hop, templates editable via CLI + admin API. |
microservice (legacy) |
A separate service-mail process on each core bound to 127.0.0.1:9000 |
Disk files under templates/ on the service-mail box |
Existing deployments still running the standalone pryv/service-mail process. |
Everything below assumes v2 (open-pryv.io). v1 deployments configured the same two delivery paths under services.email.method: mandrill | microservice in core/core/conf/core.json, with templates in a separate pryv/mail Docker container or via Mandrill’s hosted templates — that surface is no longer used in v2.
Choose a method
Section titled “Choose a method ”Set services.email.method in override-config.yml. Default is microservice for now; a future release will flip the default to in-process once both modes have had equal prod exposure.
services: email: method: in-process # or 'microservice' enabled: welcome: true resetPassword: trueCommon config — SMTP, sender, language
Section titled “Common config — SMTP, sender, language ”These apply to both methods. SMTP credentials and the sender identity are always per-core, local to override-config.yml — they do not propagate through PlatformDB.
services: email: defaultLang: en # applied when the request has no `language` field welcomeTemplate: welcome-email resetPasswordTemplate: reset-password from: name: 'Pryv Lab no-reply' address: 'no-reply@your-domain.example' smtp: host: your-smtp-server port: 587 secure: false auth: user: REPLACE_ME pass: REPLACE_MENeed to use sendmail instead of SMTP for dev? Pass smtp: { sendmail: true, path: '/usr/sbin/sendmail' } — nodemailer honours the same field names as the previous service-mail layer.
in-process mode (recommended)
Section titled “in-process mode (recommended) ”In-process mode renders Pug templates inside the api-server workers that already handle registration and password-reset. Templates live in the cluster-wide PlatformDB (rqlite) and propagate automatically to every core.
Boot-time template seeding
Section titled “Boot-time template seeding ”On the first boot with an empty PlatformDB, the master will seed templates from an on-disk Pug directory if you point it at one:
services: email: method: in-process templatesRootDir: /opt/open-pryv.io/mail-templatesDirectory layout expected:
/opt/open-pryv.io/mail-templates/├── welcome-email/│ ├── en/│ │ ├── subject.pug│ │ └── html.pug│ └── fr/│ ├── subject.pug│ └── html.pug└── reset-password/ └── en/ ├── subject.pug └── html.pugSeeding is idempotent: if PlatformDB already has any mail-template/* row the master skips the seed and logs the count. Re-seeding after the first boot is the job of the CLI / admin API below — changing the files on disk does NOT re-seed.
If templatesRootDir is empty, no templates are seeded. You can instead populate PlatformDB from scratch using the CLI templates seed --from <dir> or the PUT /system/admin/mail/templates/:type/:lang/:part admin route — both overwrite existing rows.
Managing templates — bin/mail.js CLI
Section titled “Managing templates — bin/mail.js CLI ”Run from inside the open-pryv.io directory on any core:
node bin/mail.js templates list# → type lang part len# welcome-email en html 482# welcome-email en subject 18# ...
node bin/mail.js templates get welcome-email en html# → prints the current Pug source to stdout
node bin/mail.js templates set welcome-email en html --file ./new-welcome.pug# → overwrites the html part. CLI doesn't push IPC; sibling workers refresh# on their next request via the admin API path or the periodic cache re-read.
node bin/mail.js templates delete welcome-email fr # wipes both parts for frnode bin/mail.js templates delete welcome-email fr subject # wipes only subject
node bin/mail.js templates seed --from /opt/open-pryv.io/mail-templates# → OVERWRITES every row that exists on disk. Use this to bulk-replace.
node bin/mail.js send-test welcome-email en alice@example.com# → renders the template with stub substitutions and sends a real email# through the configured SMTP transport.Managing templates — admin HTTP API
Section titled “Managing templates — admin HTTP API ”All routes live under /system/admin/mail/ on every core and require the platform admin key (auth.adminAccessKey) as the Authorization header. Unauthorized requests return 404 (by design, to avoid advertising the surface).
| Method | Path | Body | Response |
|---|---|---|---|
GET |
/system/admin/mail/templates |
— | { templates: [{type,lang,part,length}] } |
GET |
/system/admin/mail/templates/:type/:lang/:part |
— | text/plain raw Pug |
PUT |
/system/admin/mail/templates/:type/:lang/:part |
{ "pug": "<source>" } |
204 |
DELETE |
/system/admin/mail/templates/:type/:lang/:part |
— | 204 |
POST |
/system/admin/mail/send-test |
{ type, lang, recipient } |
{ sent: true } |
PUT and DELETE both trigger a cross-worker refresh on the local core via IPC so the new content is live on the next request without a restart.
Example:
ADMIN_KEY=...curl -sS -X PUT https://core-use1.example/system/admin/mail/templates/welcome-email/en/subject \ -H "Authorization: $ADMIN_KEY" \ -H "Content-Type: application/json" \ --data-binary '{ "pug": "| Welcome to Example" }'PlatformDB keyspace
Section titled “PlatformDB keyspace ”Templates are stored as raw Pug strings under:
mail-template/<type>/<lang>/<part><part> is subject or html. The value is compiled on demand at render time; the compiled function is cached in the worker’s memory alongside the raw source. A refresh nudge (IPC broadcast or process restart) drops the compiled cache too.
Cluster propagation
Section titled “Cluster propagation ”- Same core, multiple workers — after a
PUTorDELETE, the worker that handled the write sendsmail:template-invalidateover IPC. Master broadcasts it to every sibling worker; each sibling re-materialises its local tmp-dir of Pug sources on receipt. - Across cores — rqlite replicates the
mail-template/*row to every other core. The next request on those cores reads the new value directly from PlatformDB on a refresh. No cross-core IPC needed. - New core joining the cluster — a freshly bootstrapped core sees the existing templates via rqlite replication as soon as it joins the Raft group. No re-seed needed.
microservice mode (legacy)
Section titled “microservice mode (legacy) ”If you are still running the standalone pryv/service-mail process alongside each core, set:
services: email: method: microservice url: http://127.0.0.1:9000/sendmail/ key: your-shared-auth-key # matches http.auth on the service-mail side- Templates live on disk under
service-mail/templates/<type>/<lang>/{subject,html}.pug. Edit, restart, repeat — no hot reload. services.email.smtp.*andservices.email.from.*in open-pryv.io are ignored in this mode; SMTP creds live on the service-mail side.- The
pryv/service-mailGitHub repo is supported for the v2 2.0.0 line. It will be archived oncein-processbecomes the default.
Template variables
Section titled “Template variables ”Pug templates receive a locals object at render time. The two shipped types expect:
welcome-email
Section titled “welcome-email”| Local | Example |
|---|---|
username |
alice |
email |
alice@example.com |
reset-password
Section titled “reset-password”| Local | Example |
|---|---|
username |
alice |
email |
alice@example.com |
resetUrl |
https://sw.example.com/access/reset-password.html |
resetToken |
32-char opaque token |
Use #{var} in Pug to interpolate.
SPF record reminder
Section titled “SPF record reminder ”Whichever method you pick, SMTP servers use SPF to verify the sender. If you’re emitting mail on behalf of your Pryv.io domain, add a TXT record to your DNS zone authorising your SMTP host:
@ 10800 IN TXT "v=spf1 include:spf.your-smtp-host.example ~all"See DNS configuration for where to put it in your zone.

