Email and Upload Providers
2 Strapi features, Email and the Media Library, can be extended via the installation and configuration of additional providers.
Providers add an extension to the core capabilities of the plugin, for example to upload media files to AWS S3 instead of the local server, or using Amazon SES for emails instead of Sendmail.
There are both official providers maintained by Strapi — discoverable via the Marketplace — and many community maintained providers available via npm.
A provider can be configured to be private to ensure asset URLs will be signed for secure access.
Installing providers
New providers can be installed using npm
or yarn
using the following format @strapi/provider-<plugin>-<provider> --save
.
For example:
- yarn
- npm
Install the AWS S3 provider for the Upload (Media Library) feature:
yarn add @strapi/provider-upload-aws-s3
Install the Sendgrid provider for the Email feature:
yarn add @strapi/provider-email-sendgrid
Install the AWS S3 provider for the Upload (Media Library) feature:
npm install @strapi/provider-upload-aws-s3 --save
Install the Sendgrid provider for the Email feature:
npm install @strapi/provider-email-sendgrid --save
Configuring providers
Newly installed providers are enabled and configured in the /config/plugins
file. If this file does not exist you must create it.
Each provider will have different configuration settings available. Review the respective entry for that provider in the Marketplace or npm to learn more.
The following are example configurations for the Upload (Media Library) and Email features:
- Upload (Media Library)
- JavaScript
- TypeScript
module.exports = ({ env }) => ({
// ...
upload: {
config: {
provider: 'aws-s3',
providerOptions: {
baseUrl: env('CDN_URL'),
rootPath: env('CDN_ROOT_PATH'),
s3Options: {
credentials: {
accessKeyId: env('AWS_ACCESS_KEY_ID'),
secretAccessKey: env('AWS_ACCESS_SECRET'),
},
region: env('AWS_REGION'),
params: {
ACL: env('AWS_ACL', 'public-read'),
signedUrlExpires: env('AWS_SIGNED_URL_EXPIRES', 15 * 60),
Bucket: env('AWS_BUCKET'),
},
},
},
actionOptions: {
upload: {},
uploadStream: {},
delete: {},
},
},
},
// ...
});
export default ({ env }) => ({
// ...
upload: {
config: {
provider: 'aws-s3', // For community providers pass the full package name (e.g. provider: 'strapi-provider-upload-google-cloud-storage')
providerOptions: {
accessKeyId: env('AWS_ACCESS_KEY_ID'),
secretAccessKey: env('AWS_ACCESS_SECRET'),
region: env('AWS_REGION'),
params: {
ACL: env('AWS_ACL', 'public-read'), // 'private' if you want to make the uploaded files private
Bucket: env('AWS_BUCKET'),
},
},
},
},
// ...
});
Strapi has a default security
middleware that has a very strict contentSecurityPolicy
that limits loading images and media to "'self'"
only, see the example configuration on the provider page or the middleware documentation for more information.
- JavaScript
- TypeScript
module.exports = ({ env }) => ({
// ...
email: {
config: {
provider: 'sendgrid', // For community providers pass the full package name (e.g. provider: 'strapi-provider-email-mandrill')
providerOptions: {
apiKey: env('SENDGRID_API_KEY'),
},
settings: {
defaultFrom: 'juliasedefdjian@strapi.io',
defaultReplyTo: 'juliasedefdjian@strapi.io',
testAddress: 'juliasedefdjian@strapi.io',
},
},
},
// ...
});
export default ({ env }) => ({
// ...
email: {
config: {
provider: 'sendgrid', // For community providers pass the full package name (e.g. provider: 'strapi-provider-email-mandrill')
providerOptions: {
apiKey: env('SENDGRID_API_KEY'),
},
settings: {
defaultFrom: 'juliasedefdjian@strapi.io',
defaultReplyTo: 'juliasedefdjian@strapi.io',
testAddress: 'juliasedefdjian@strapi.io',
},
},
},
// ...
});
- When using a different provider per environment, specify the correct configuration in
/config/env/${yourEnvironment}/plugins.js|ts
(See Environments). - Only one email provider will be active at a time. If the email provider setting isn't picked up by Strapi, verify the
plugins.js|ts
file is in the correct folder. - When testing the new email provider with those two email templates created during strapi setup, the shipper email on the template defaults to
no-reply@strapi.io
and needs to be updated according to your email provider, otherwise it will fail the test (See Configure templates locally).
Configuration per environment
When configuring your provider you might want to change the configuration based on the NODE_ENV
environment variable or use environment specific credentials.
You can set a specific configuration in the /config/env/{env}/plugins.js|ts
configuration file and it will be used to overwrite the default configuration.
Creating providers
To implement your own custom provider you must create a Node.js module.
The interface that must be exported depends on the plugin you are developing the provider for. The following are templates for the Upload (Media Library) and Email features:
- Upload (Media Library)
- JavaScript
- TypeScript
module.exports = {
init(providerOptions) {
// init your provider if necessary
return {
upload(file) {
// upload the file in the provider
// file content is accessible by `file.buffer`
},
uploadStream(file) {
// upload the file in the provider
// file content is accessible by `file.stream`
},
delete(file) {
// delete the file in the provider
},
checkFileSize(file, { sizeLimit }) {
// (optional)
// implement your own file size limit logic
},
getSignedUrl(file) {
// (optional)
// Generate a signed URL for the given file.
// The signed URL allows secure access to the file.
// Only Content Manager assets will be signed.
// Returns an object {url: string}.
},
isPrivate() {
// (optional)
// if it is private, file urls will be signed
// Returns a boolean
},
};
},
};
export default {
init(providerOptions) {
// init your provider if necessary
return {
upload(file) {
// upload the file in the provider
// file content is accessible by `file.buffer`
},
uploadStream(file) {
// upload the file in the provider
// file content is accessible by `file.stream`
},
delete(file) {
// delete the file in the provider
},
checkFileSize(file, { sizeLimit }) {
// (optional)
// implement your own file size limit logic
},
getSignedUrl(file) {
// (optional)
// Generate a signed URL for the given file.
// The signed URL allows secure access to the file.
// Only Content Manager assets will be signed.
// Returns an object {url: string}.
},
isPrivate() {
// (optional)
// if it is private, file urls will be signed
// Returns a boolean
},
};
},
};
- JavaScript
- TypeScript
module.exports = {
init: (providerOptions = {}, settings = {}) => {
return {
send: async options => {},
};
},
};
export {
init: (providerOptions = {}, settings = {}) => {
return {
send: async options => {},
};
},
};
In the send function you will have access to:
providerOptions
that contains configurations written inplugins.js|ts
settings
that contains configurations written inplugins.js|ts
options
that contains options you send when you call the send function from the email plugin service
You can review the Strapi maintained providers for example implementations.
After creating your new provider you can publish it to npm to share with the community or use it locally for your project only.
Local providers
If you want to create your own provider without publishing it on npm you can follow these steps:
- Create a
providers
folder in your application. - Create your provider (e.g.
/providers/strapi-provider-<plugin>-<provider>
) - Then update your
package.json
to link yourstrapi-provider-<plugin>-<provider>
dependency to the local path of your new provider.
{
...
"dependencies": {
...
"strapi-provider-<plugin>-<provider>": "file:providers/strapi-provider-<plugin>-<provider>",
...
}
}
- Update your
/config/plugins.js|ts
file to configure the provider. - Finally, run
yarn
ornpm install
to install your new custom provider.
Creating private providers
You can set up a private provider, meaning that every asset URL displayed in the Content Manager will be signed for secure access.
To enable private providers, you must implement the isPrivate()
method and return true
.
In the backend, Strapi generates a signed URL for each asset using the getSignedUrl(file)
method implemented in the provider. The signed URL includes an encrypted signature that allows the user to access the asset (but normally only for a limited time and with specific restrictions, depending on the provider).
Note that for security reasons, the content API will not provide any signed URLs. Instead, developers using the API should sign the urls themselves.
Example
To create a private aws-s3
provider:
- Create a
/providers/aws-s3
folder in your application. See Local Providers for more information. - Implement the
isPrivate()
method in theaws-s3
provider to returntrue
. - Implement the
getSignedUrl(file)
method in theaws-s3
provider to generate a signed URL for the given file.
- JavaScript
- TypeScript
// aws-s3 provider
module.exports = {
init: (config) => {
const s3 = new AWS.S3(config);
return {
async upload(file) {
// code to upload file to S3
},
async delete(file) {
// code to delete file from S3
},
async isPrivate() {
return true;
},
async getSignedUrl(file) {
const params = {
Bucket: config.params.Bucket,
Key: file.path,
Expires: 60, // URL expiration time in seconds
};
const signedUrl = await s3.getSignedUrlPromise("getObject", params);
return { url: signedUrl };
},
};
},
};
// aws-s3 provider
export = {
init: (config) => {
const s3 = new AWS.S3(config);
return {
async upload(file) {
// code to upload file to S3
},
async delete(file) {
// code to delete file from S3
},
async isPrivate() {
return true;
},
async getSignedUrl(file) {
const params = {
Bucket: config.params.Bucket,
Key: file.path,
Expires: 60, // URL expiration time in seconds
};
const signedUrl = await s3.getSignedUrlPromise("getObject", params);
return { url: signedUrl };
},
};
},
};