Skip to main content

Custom Welcome Emails

When a new project membership is created, either by "invite" or self "register", by default Medplum sends a "Welcome" email with account setup instructions for the configured "app" URL. For example, on Medplum's hosted environment, the email will include a link to "".

Medplum fully supports creating a white-label experience where users do not see any Medplum branding. That includes overriding all email behavior.

This document describes the steps to send custom Welcome email messages.

In short, here are the key steps:

  1. Create a "Set Password" page in your application
  2. Create a Medplum Bot that processes new ProjectMembership resources
  3. Create a FHIR Subscription that connects ProjectMembership resources to the bot

Set Password Page

In your custom application, you will need a "Set Password" page. This will be the page where users go to confirm their email address. For a full example of a "Set Password" page, check out the source to SetPasswordPage.tsx for the Medplum App.

Key functions of the page:

  • Receives id and secret from URL parameters
  • Prompts the user for password and confirmPassword
  • Verifies that password and confirmPassword match
  • Sends the id, secret, and password to the /auth/setpassword API endpoint

New Membership Bot

Create a Medplum Bot to handle new ProjectMembership resources. The bot will send a custom email message to the user.


If you are new to Medplum Bots, you may want to read the Bots documentation first.

This Bot will use ProjectMembership and PasswordChangeRequest resources, so the Bot must be a "Project Admin" to access these resources.

Here is a full example of a Bot that sends a custom email message:

import { BotEvent, getDisplayString, MedplumClient, ProfileResource } from '@medplum/core';
import { PasswordChangeRequest, ProjectMembership, Reference } from '@medplum/fhirtypes';

export async function handler(medplum: MedplumClient, event: BotEvent<ProjectMembership>): Promise<any> {
// This Bot executes on every new ProjectMembership resource.
// ProjectMembership is an administrative resource that connects a User and a Project.
// ProjectMembership resources are only available to project administrators.
// Therefore, this Bot must be configured as a project admin.
const membership = event.input;

// From the ProjectMembership, we can retrieve the user's profile.
// Here, "profile" means FHIR profile: the FHIR resource that represents the user's identity.
// In general, the profile will be a FHIR Patient or a FHIR Practitioner.
const profile = await medplum.readReference(membership.profile as Reference<ProfileResource>);

// Get the email from the profile.
// Note that email is not a required field, so you may want to add
// custom business logic for your unique circumstances.
const email = profile.telecom?.find((c) => c.system === 'email')?.value as string;

// When a new user registers or is invited to a project,
// a PasswordChangeRequest resource is automatically created for initial account setup.
// PasswordChangeRequest resources are readonly, and only available to project admins.
const pcr = (await medplum.searchOne('PasswordChangeRequest', {
_sort: '-_lastUpdated',
user: membership.user?.reference as string,
})) as PasswordChangeRequest;

// Generate the setPasswordUrl based on the id and secret.
// You will need to use these values in your application to confirm the user account.
const setPasswordUrl = `${}/${pcr.secret}`;

// Now we can send the email to the user.
// This is a simple plain text email to the user.
// Medplum supports sending HTML emails as well via the nodemailer API.
// Learn more:
await medplum.sendEmail({
to: email,
subject: 'Welcome to Example Health!',
text: [
`Hello ${getDisplayString(profile)}`,
'Please click on the following link to create your account:',
'Thank you,',
'Example Health',

return true;

Create, save, and deploy your bot. Make note of the Bot ID.

FHIR Subscription

Create a FHIR Subscription that connects ProjectMembership resources to the bot. The subscription will trigger the bot when a new ProjectMembership resource is created.

Go to Subscriptions and click "New...".

Enter the following values:

  • Status = active
  • Reason = New membership
  • Criteria = ProjectMembership
  • Channel Type = rest-hook
  • Channel Endpoint = Bot/YOUR_BOT_ID


To test your custom welcome email, create a new user account. The user will receive a custom email message.