Top External Email Providers for Your Strapi Application

Michael - Jun 4 - - Dev Community

Email is one of the most critical communication channels between businesses and their users. It can be used to send notifications, updates, newsletters, offers, or other communications. A global study showed that 83% of people prefer to receive communications from businesses over email.

Going with an external email provider has many benefits, and Strapi offers a wide array of options and ways to integrate them into your application.

This article aims to simplify your decision-making process by gathering all the necessary resources in one place. We will compare these providers, helping you choose the one that best suits your application.

Additionally, we will provide code examples and guide you through integrating this functionality into your Strapi projects, making the process more convenient and straightforward.

What is Strapi?

Strapi is an open-source headless CMS (Content Management System) that allows you to quickly and easily create an API for content-rich applications. Unlike traditional CMS, it decouples the backend from the frontend, allowing you to pick whatever UI framework you're most comfortable with, meaning you can better create faster and more personalized experiences for your customers.

External Email Providers

While Strapi provides us with powerful ways to manage content and user data, using an external email provider comes with several benefits.

Benefits of Email Providers

  • They are reliable as they invest heavily in infrastructure, anti-spam measures, and deliverability
  • They are scalable: as your application grows, so too will the number of emails you send.
  • An external email provider has the ability to handle large email volumes without compromising on performance or deliverability,
  • They get rid of the need for your developers to manage email server infrastructure.
  • They also offer a lot of different features for you to take advantage of and follow best practices when it comes to security.

How to choose

Strapi's flexibility allows us to combine it with a wide range of email service providers, such as Mailgun, Resend, Sendgrid, Nodemailer, and AWS SES. We'll review and compare the advantages of each.

There are many things to consider when selecting an email service provider. For instance, imagine an up-and-coming e-commerce platform experiencing rapid growth in its customer base and transactional email volume. In this case, it may want to go for a more reliable service, such as AWS SES, which will ensure reliable handling of increased email volume without compromising on deliverability and speed.

On the other hand, let's consider a more content-focused website powered by Strapi, where personalised news letters and email campaigns are key to the business's success. In this case, a feature-rich solution like Sendgrid, with its segmentation, A/B testing, and campaign analytics, would be a great fit. This example underscores the importance of first understanding your project requirements and then aligning them with the most suitable provider, a strategy that can significantly enhance your email marketing efforts.

Advantages of Using Strapi with Email Providers

Strapi provides a great content management system; we can easily pull in user-specific data, such as names or preferences, and inject them into our email templates to make them more engaging. Strapi is scalable and offers a user-friendly interface with built-in API capabilities, which will help streamline the development process and reduce the time and effort it would cost to build something similar with another framework such as express.js.

Let's examine each provider individually to see what they offer and how they compare to each other.

Resend Email Provider

First up, we have Resend, which is an email service provider that helps optimise transactional emails and email campaigns. It offers a collection of tools to simplify the process of sending marketing emails, making sure they reach the correct recipients effectively and not the spam folder. With Resend's free plan, you can send 100 emails per day.

Resend Features

Resend has a test mode, so you can experiment with their API without the risk of sending accidental emails. They also offer modular webhooks, so you can receive real-time notifications letting you know when emails are delivered, opened, bounced, or even if a link inside is clicked. Another great feature of Resend is that you can develop email templates with React, getting rid of the need to use confusing table layouts.

The paid version of Resend offers a multi-region option, which allows you to send emails from the region closest to your users, so you can be sure they receive your emails in a timely and efficient manner. They also offer a dedicated IP for those companies who wish to avoid a shared IP and maintain complete control over their reputation.

Resend also offers open and click tracking, which allows developers to track engagement and tune their sending approach. This allows you to identify which of your customers or users are most interested in receiving your messages.

Key features:

  • Multi-language support.
  • CRM integrations with Hubspot, ActiveCampaign, etc..
  • Link tracking, open & click tracking.
  • Behaviour-based subscriber segmentation.
  • Automated welcome and follow-up flows.
  • Inbox placement and spam testing.

Strapi and Resend Integration

Install Strapi

Create a folder that will contain the source code for the project. Open a terminal and navigate to a directory of your choice, and run the below commands:

mkdir strapi-email-tutorial
cd strapi-email-tutorial
Enter fullscreen mode Exit fullscreen mode

Now, let's create our Strapi project with the command below:

npx create-strapi-app@latest strapi-email
Enter fullscreen mode Exit fullscreen mode

You can enter y to proceed and select quickstart

Once that has finished installing, you should see a confirmation such as the below:
install-strapi.png

Obtain Resend API Key

Now before we write any code, let's obtain an API key for Resend. Go to the following address: https://resend.com/overview, sign in, and get the API key; there should be an option to generate one on the dashboard.

Now navigate to the route of the strapi project in the terminal and run the following to install the Strapi plugin for Resend:

yarn add strapi-provider-email-resend
Enter fullscreen mode Exit fullscreen mode

Copy the following code and replace with the code in the config/plugins.js. Make sure to add the RESEND_API_KEY variable to your .env file, with the value being the key you generated with Resend. Also, use your normal email account for the defaultFrom and defaultTo fields.

module.exports = ({ env }) => ({
  email: {
    config: {
      provider: 'strapi-provider-email-resend',
      providerOptions: {
        apiKey: env('RESEND_API_KEY'), // Required
      },
      settings: {
        defaultFrom: 'YOUR_EMAIL_HERE',
        defaultReplyTo: 'YOUR_EMAIL_HERE',
      },
    }
  },    
});
Enter fullscreen mode Exit fullscreen mode

Generate Custom Email API

Now we have the Resend plugin setup in our project we should be able to use the package in one of our API's, let's first generate a custom API and write the code, navigate to the terminal and run the below command in the root directory:

yarn strapi generate
Enter fullscreen mode Exit fullscreen mode

This will begin the process of generating our own custom API. Choose the API option, give it the name email-test, and select "no" when it asks us if this is for a plugin.

Inside the src directory, If we check the api directory in our code editor, we should see the newly created API for email-test with it's route, controller, and service.

001-api-creation.png

Enable Public API Access

By default, Strapi requires authentication to query our API and receive information, but that is outside the scope of this tutorial. Instead, we will make our API publicly accessible. We can find more about authentication and REST API in this blog post.

002-enable-strapi-api-public.png

Navigate to the Strapi admin dashboard, From the left sidebar, click on Settings. Again,  on the left panel under USERS & PERMISSIONS PLUGIN, click on Roles, then click on Public from the table on the right. Now scroll down, click on Email-test, and tick Select all then save in the top right which will allow us to hit this endpoint without authentication.

Modify Custom Email Route

Now under the src/api/email-test directory, locate the routes directory. There you will find email-test.js file. Replace the code inside this file with the following:

module.exports = {
  routes: [
    {
      method: "POST",
      path: "/email-test/exampleAction",
      handler: "email-test.exampleAction",
      config: {
        policies: [],
        middlewares: [],
      },
    },
  ],
};
Enter fullscreen mode Exit fullscreen mode

Modify Custom Email Controller

Change the code in the src/api/controllers/email-test.js file to the following:

module.exports = {
  exampleAction: async (ctx, next) => {
    try {
      const res = await strapi
        .service("api::email-test.email-test")
        .emailService(ctx);
      ctx.body = res.message;
    } catch (err) {
      ctx.body = err;
    }
  },
};
Enter fullscreen mode Exit fullscreen mode

Modify Custom Email Service

Also, change the code in the src/api/services/email-test.js directory to the following:

module.exports = ({ strapi }) => ({
  emailService: async (ctx) => {
    try {
      const input = ctx.request.body.data?.input;
      const emailTo = ctx.request.body.data?.emailTo;
      await strapi.plugins["email"].services.email.send({
        from: "onboarding@resend.dev",
        to: emailTo,
        subject: "Hello World",
        html: `<p>${input}</p>`,
      });

      return {
        message: "Email sent!",
      };
    } catch (err) {
      ctx.body = err;
    }
  },
});
Enter fullscreen mode Exit fullscreen mode

You should now be able to test the Resend email integration with the following code in your terminal, make sure you replace YOUR_EMAIL_HERE with your actual email address.

curl -X POST \
  http://localhost:1337/api/email-test/exampleAction \
  -H 'Content-Type: application/json' \
  -d '{
    "data": {
        "input": "This is a test email to check the integration.",
        "emailTo": "YOUR_EMAIL_HERE"
    }
}'
Enter fullscreen mode Exit fullscreen mode

Sendgrid Email Provider

Sendgrid focuses on email delivery, automation and real-time analytics it allows users to send transactional and marketing emails at scale, it offers a 99% deliverability rate and has AI-powered deliverability, and email marketing, email automation and multichannel advertising products. With Sengrids free plan, you can send 100 emails per day.

Sendgrid Features

Key features include

  • Dedicated IP addresses to improve deliverability
  • Integrations with e-commerce platforms like shopify and BigCommerce
  • A/B testing capabilities
  • Automated workflows with templates
  • Contact segmentation for targeted campaigns
  • In-depth email and click analytics

Sendgrid vs Resend

In terms of deliverability, Sendgrid provides dedicated IPs for improved sender reputation and inboxing; it has average industry deliverability rates compared to Resend, which heavily optimises campaigns for maximum inbox placement, maintaining exceptional IP reputations. Both platforms provide good deliverability that meets or exceeds industry standards.

When we look at Automation and workflow for campaigns both Sendgrid and Resend provide easy to use drag-and-drop workflow builders to create sequences and triggers. For multi-step campaigns, Resend seems to be the best at building conditional logic across workflows but Sendgrid also allows multi-path workflows. In terms of segmentation and targeting Resend has the strongest features for dynamically inserting subscriber data into emails, Sendgrid allows some personalisation. Sendgrid imposes contact limits whereas Resend allows unlimited segments.

Sendgrid seems to have the most integrations and plugins available, with extensive documentation, Resend has fewer out of the box integrations.

In terms of analytics Sendgrid has the most powerful segmentation capabilities for analyzing your email data, allowing you to deeply filter your reports, while Resend visual reports and insights are simplest to digest Sendgrid provides greater raw data access.

As a conclusion to this quick comparison between these two email providers I think Resend is best for beginners, with easy workflow automation, campaign building and visual reporting whereas Sendgrid provides the greatest email volume scalability and add-on integrations, It also offers robust targeting and analytics for experts.

Strapi and Sendgrid Integration

We can use a Strapi plugin to integrate Sendgrid just like we did with Resend, first of all let's remove the Resend integration, navigate to your terminal and run the below command in the root directory.

Install Sendgrid Strapi Plugin

yarn remove strapi-provider-email-resend
Enter fullscreen mode Exit fullscreen mode

With that package removed, run the below to install the Sendgrid plugin.

yarn add @strapi/provider-email-sendgrid
Enter fullscreen mode Exit fullscreen mode

Modify Plugin Configuration

Now navigate to your config/plugins.js file and replace the code in there with the below:

module.exports = ({ env }) => ({
  email: {
    config: {
      provider: "sendgrid",
      providerOptions: {
        apiKey: env("SENDGRID_API_KEY"), // Required
      },
      settings: {
        defaultFrom: "YOUR_EMAIL_HERE",
        defaultReplyTo: "YOUR_EMAIL_HERE",
      },
    },
  },
});
Enter fullscreen mode Exit fullscreen mode

Make sure to head on over to sendgrid and create a free account, then navigate to settings and create an API key.

Add Sendgrid API Key to Environment Variable

You can then add it to your .env file so the above integration works.

SENDGRID_API_KEY=YOUR_SENDGRID_API_KEY
Enter fullscreen mode Exit fullscreen mode

Modify Email Service

Now restart the project and the only thing you will need to change is the from field in the src/api/email-test/services/email-test.js file as below:

 await strapi.plugins["email"].services.email.send({
        from: "YOUR_EMAIL_HERE",
        to: email,
        subject: "Hello World",
        html: `<p>${input}</p>`,
      });
Enter fullscreen mode Exit fullscreen mode

Test Sendgrid Email Provider

Seeing that the rest of the code is in place from the previous Resend integration if you run the below code in the terminal it should send an email using Sendgrid.

curl -X POST \
  http://localhost:1337/api/email-test/exampleAction \
  -H 'Content-Type: application/json' \
  -d '{
    "data": {
        "input": "This is a test email to check the integration.",
        "emailTo": "YOUR_EMAIL_HERE"
    }
}'
Enter fullscreen mode Exit fullscreen mode

Nodemailer Email Provider

Nodemailer is a module developed in 2010 to simplify email sending. It has a flexible and easy-to-use interface and utilizes various email services or SMTP servers, including EmailEngine. This self-hosted email gateway allows you to make REST requests against IMAP and SMTP servers. This makes Nodemailer more flexible, as it gives you a choice to use different email services or SMTP servers based on your requirements. Note that while it is free to use Nodemailer, you may incur costs depending on the email service you choose.

Differentiation From Hosted Email Services

Nodemailer allows us to send emails directly from our Node applications. Hosted email service providers like Sendgrid, on the other hand, differ. For example, hosted email services provide a dedicated and reliable infrastructure, typically offer a broad range of features beyond sending basic emails, are easier to use, and will more often than not operate on some sort of subscription-based model.

So in comparison, just to recap, Nodemailer gives us flexibility in choosing the email transport method and supports various options: SMTP,sendmail, Amazon SES, and more. Nodemailer focuses on core email sending functionality, allowing developers to send emails programatically from their applications. It gives us some basic features like email composition, attachment support, and error handling.

Strapi and NodeMailer Integration

For Nodemailer to work we will need to provide it with an SMTP service and the auth credentials, let's use Ethereal which is a fake SMTP service. navigate to - https://ethereal.email and click the button to create an Ethereal account.

003-nodemailer-configuration.png

Now you should be directed to a page like the above, jot down the credentials somewhere as we will use these later.

Install NodeMailer Strapi Plugin

Now navigate back to your terminal and go to the root directory. Remove the previous plugin with the following command:

yarn remove @strapi/provider-email-sendgrid
Enter fullscreen mode Exit fullscreen mode

And add the Strapi nodemailer plugin by running the below:

yarn add @strapi/provider-email-nodemailer
Enter fullscreen mode Exit fullscreen mode

Update Configuration

Once that has finished let's add the plugin integration code to the config/plugins.js file, remember you will need to create the SMTP_USERNAME and SMTP_PASSWORD variables in your .env file and fill their values with the info you obtained from ethereal mail:

module.exports = ({ env }) => ({
  email: {
    config: {
      provider: 'nodemailer',
      providerOptions: {
        host: env('SMTP_HOST', 'smtp.ethereal.email'),
        port: env('SMTP_PORT', 587),
        auth: {
          user: env('SMTP_USERNAME'),
          pass: env('SMTP_PASSWORD'),
        },
      },
      settings: {
        defaultFrom: 'hello@example.com',
        defaultReplyTo: 'hello@example.com',
      },
    },
  },
});
Enter fullscreen mode Exit fullscreen mode

Update Email Service

Update the email code in the src/api/email-test/services/email-test.js file with the following:

  await strapi.plugins["email"].services.email.send({
        from: "YOUR_ETHEREAL_MAIL",
        to: email,
        subject: "Hello World",
        html: `<p>${input}</p>`,
      });
Enter fullscreen mode Exit fullscreen mode

Run the below code in your terminal to see Nodemailer in action remembering to replace the emailTo with your email:

Test NodeMailer Email Provider

curl -X POST \
  http://localhost:1337/api/email-test/exampleAction \
  -H 'Content-Type: application/json' \
  -d '{
    "data": {
        "input": "This is a test email to check the integration.",
        "emailTo": "YOUR_EMAIL_HERE"
    }
}'
Enter fullscreen mode Exit fullscreen mode

As ethereal is a fake SMTP provider, it won't actually send the email, but you can navigate back to ethereal and look under the Messages tab (this tab captures all of the outgoing and incoming mail), and you will be able to see the outgoing email that Nodemailer just connected with ethereal to send, confirming that the integration was successful.

AWS SES Email Provider

Amazon Simple Email Service (SES) is a cloud-based email service provided by Amazon Web Services. It allows you to send transactional, marketing, and notification emails, much like Resend and Sendgrid. It offers an extensive set of features, such as improved inbox deliverability with a virtual deliverability manager so you can reach inboxes instead of spam or junk, flexible deployment options such as shared or dedicated IP addresses, a console so you can view important analytics such as number of sends, opens, clicks, bounces, etc, and it supports all industry-standard authentication mechanisms.

AWS SES Features

key features include

  • Reliable Email Sending
  • High Deliverability
  • SMTP and API-based Sending
  • Email Templates
  • Bounce and Complaint Handling
  • Email Analytics
  • Dedicated IP Addresses
  • Integration with AWS Services
  • Cost-effective Pricing

In terms of pricing, Amazon SES will allow you to send 3000 messages per month for 12 months completely free. In comparison, Resend and Sendgrid offer the same amount of emails but don't give you a 12-month time period, suggesting you can stay on their free tier until you scale up. However,  upon closer inspection, Amazon's paid service is actually cheaper. 20,000 emails a month will cost you $2 per month, while with Resend or Sendgrid, that will set you back $20 per month. This suggests that if you intend to scale rapidly, Amazon would be a better choice.

I would say one of the main standout features of AWS SES is its ability to integrate with other services on the AWS platform. You can configure it to be used on a site hosted on EC2 and set up some custom notifications with Simple Notification Service (SNS), for example. It might also be worth mentioning if you plan to use AWS EC2 for your hosting. AWS gives you the first 62,000 emails per month absolutely free.

Strapi and AWS SES Integration

Now to integrate this service with Strapi we can use a plugin but we will also need to create an AWS account to configure Amazon SES and get the correct credentials to connect.

First navigate to AWS at - https://aws.amazon.com create an account and then on the dashboard search for Amazon SES, click get started and then you should be directed to a dashboard like this

004-add-email-to-aws-ses.png

You can just add your email address here, then click next.

005-add-sending-domain-to-aws-ses.png

Here you can just add the domain of your email and click next on all of the following options.

Then you can click in the top right dropdown and navigate to security credentials scroll down and click to create an access key then copy the Access key and the Secret somewhere safe.

Install NodeMailer Strapi Plugin

Now you can navigate to the root of your project and remove the previous integration with the following command:

yarn remove @strapi/provider-email-nodemailer
Enter fullscreen mode Exit fullscreen mode

And then add the AWS SES Strapi plugin by running the below command

yarn add @strapi/provider-email-amazon-ses
Enter fullscreen mode Exit fullscreen mode

Update Configuration

Navigate to ./config/plugins.js and paste in the following integration code

module.exports = ({ env }) => ({
  email: {
    config: {
      provider: 'amazon-ses',
      providerOptions: {
        key: env('AWS_SES_KEY'),
        secret: env('AWS_SES_SECRET'),
        amazon: 'https://email.us-east-1.amazonaws.com',
      },
      settings: {
        defaultFrom: 'myemail@protonmail.com',
        defaultReplyTo: 'myemail@protonmail.com',
      },
    },
  },
});
Enter fullscreen mode Exit fullscreen mode

Update Email Service

Now add the AWS access and secret key you got earlier to the .env file with the relevant variable names.

And in src/api/email-test/services/email-test.js file, you will just need to change the email from the previous ethereal email to the one you used for SES:

  await strapi.plugins["email"].services.email.send({
        from: "YOUR_EMAIL_HERE",
        to: email,
        subject: "Hello World",
        html: `<p>${input}</p>`,
      });
Enter fullscreen mode Exit fullscreen mode

Now that we've set up the integration we can use this curl command in the terminal to simulate the api call and watch Amazon SES in action

Test AWS SES Provider

curl -X POST \
  http://localhost:1337/api/email-test/exampleAction \
  -H 'Content-Type: application/json' \
  -d '{
    "data": {
        "input": "This is a test email to check the integration.",
        "emailTo": "YOUR_EMAIL_HERE"
    }
}'
Enter fullscreen mode Exit fullscreen mode

Mailgun Email Provider

Like the other email automation services we have seen so far, Mailgun offers all of the usual features, such as email sending, tracking, and analytics. What sets it apart from the crowd is its email validation service, which ensures that the email addresses you're sending mail to actually exist, this helps overall email deliverability. For instance, if you integrated this into a contact form, you could use this feature for real-time validation, and the user would be quickly notified if they entered an invalid email address.

Mailgun offers a free plan which allows you to send up to 5000 emails per month (to five authorized users of your choice) but then on the paid plan it jumps to 50,000 emails per month priced at $35 per month, clearly Mailgun free tier has limited features and it's paid plan is a little on the pricey side.

Mailgun Features

  • Email sending via API or SMTP integration
  • Email parsing and routing for inbound emails
  • Email validation to maintain a clean email list
  • Comprehensive email tracking and analytics
  • Customizable email templates for personalized campaigns
  • A/B testing to optimize email content and performance
  • Developer-friendly APIs, SDKs, and libraries
  • Scalable infrastructure for handling large email volumes
  • Compliance with email regulations (e.g., GDPR, CAN-SPAM)
  • Security features such as SPF/DKIM authentication and TLS encryption

Strapi and Mailgun Integration

To integrate Mailgun we can use the Strapi plugin to proceed, but first let's generate the api key we will need to connect to mailgun, head over to the following - https://www.mailgun.com and click "Get started for free" in the top right for Mailgun login.

006-mailgun-homepage.png

Go through the mailgun login or account creation process and once that's done you should be able to scroll down on the dashboard and select your domain.

Then if you click the dropdown for your account in the top right and click on "API security", and then you can scroll down to see your api key.

Install Mailgun Strapi Plugin

Now navigate to the root of your project in the terminal and remove the previous plugin with the below command.

yarn remove @strapi/provider-email-amazon-ses
Enter fullscreen mode Exit fullscreen mode

And add the Mailgun Strapi plugin with the following:

yarn add @strapi/provider-email-mailgun
Enter fullscreen mode Exit fullscreen mode

Update Configuration

Navigate to ./config/plugins.js and paste in the following integration code

module.exports = ({ env }) => ({
  email: {
    config: {
      provider: 'mailgun',
      providerOptions: {
        key: env('MAILGUN_API_KEY'), // Required
        domain: env('MAILGUN_DOMAIN'), // Required
        url: env(https://api.mailgun.net'), //Optional. If domain region is Europe use 'https://api.eu.mailgun.net'
      },
      settings: {
        defaultFrom: 'myemail@protonmail.com',
        defaultReplyTo: 'myemail@protonmail.com',
      },
    },
  }
});
Enter fullscreen mode Exit fullscreen mode

Making sure you add the relevant variable to your .env file.

Now you should be all set to test out the integration by running the below code in your terminal

Test Mailgun Email Provider

curl -X POST \
  http://localhost:1337/api/email-test/exampleAction \
  -H 'Content-Type: application/json' \
  -d '{
    "data": {
        "input": "This is a test email to check the integration.",
        "emailTo": "YOUR_EMAIL_HERE"
    }
}'
Enter fullscreen mode Exit fullscreen mode

Choosing the Right Email Provider

First of all, thanks to the flexibility of Strapi, there was a quick and easy way to integrate every email provider we looked at, so complexity in integration, at least where your Strapi projects are concerned, isn't an issue. All the options we looked at are great, and the one you pick will ultimately come down to your priorities and the number of emails you're sending.

Amazon SES stands out if cost-effectiveness is your primary consideration, especially if you're hosting on AWS infrastructure like an EC2 instance and anticipate rapid scaling of your service. If your focus is on enhancing your marketing efforts, then the choice is between Sendgrid and Resend, both of which offer similar features. Resend, with its user-friendly interface and easy-to-understand analytics dashboard, may be more suitable for beginners. On the other hand, Sendgrid, with its more complex and detailed features, provides more granular data.

If customizability is important and you're only concerned with basic send and receive functionality, then Nodemailer is a good option. Lastly, we have Mailgun, which isn't the cheapest solution and doesn't have the most features; if email validation is essential, it could be an option.

Conclusion

To recap, the benefits of integrating with an external email provider are numerous and include the following: enhanced email functionality, improved deliverability, scalability, analytics, and customization.

This article will help you select the right email provider for your product or business. If you still need to decide, experiment with different providers and see what works best.

Additional Resources

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .