Creating custom email providers
Page summary:
Build a custom email provider by exporting a Node.js module with a
send()function. Use it locally in your project or publish it to npm to share with the community.
Strapi's Email feature delegates sending to a provider, a Node.js module that implements a standard interface. When no official or community provider meets your needs, you can create your own.
Provider interface
To implement a custom provider you must create a Node.js module. The module must export an init function that returns a send function:
- JavaScript
- TypeScript
module.exports = {
init: (providerOptions = {}, settings = {}) => {
return {
send: async options => {},
};
},
};
export default {
init: (providerOptions = {}, settings = {}) => {
return {
send: async options => {},
};
},
};
Inside the send function you have access to:
providerOptions— the values passed underproviderOptionsin/config/plugins.js|ts.settings— the values passed undersettingsin/config/plugins.js|ts.options— the options passed when callingsend()from a controller or service.
You can review the Strapi-maintained providers for reference implementations.
Publishing and using your provider
After creating your provider you can either publish it to npm or use it locally within your project.
Publishing to npm
Publish your provider to npm to make it available to the Strapi community. Once published, install and configure it like any other provider (see Configuring providers).
Using a local provider
To use a custom provider without publishing it to npm:
- Create a
providersfolder at the root of your Strapi application. - Create your provider inside it (e.g.,
providers/strapi-provider-email-custom). - Update
package.jsonto point the dependency to the local path:
{
"dependencies": {
"strapi-provider-email-custom": "file:providers/strapi-provider-email-custom"
}
}
- Update
/config/plugins.js|tsto configure the provider. - Run
yarnornpm installto link the local package.
Private providers
A provider can be marked as private, meaning every asset URL will be signed for secure access rather than exposed as a plain URL.
To enable this, implement the isPrivate() method and return true in your provider module.
When a provider is private, Strapi uses a getSignedUrl(file) method — also implemented in the provider — to generate a signed URL for each asset. The signed URL contains an encrypted signature that grants access for a limited time and with specific restrictions, depending on your implementation.
For security reasons, the Content API does not return signed URLs. Developers consuming the API must sign URLs themselves using the provider's signing logic.