@ -0,0 +1,364 @@
|
||||
# Replacing Email Template and Sending Emails
|
||||
|
||||
## Introduction
|
||||
|
||||
Hi, in this step by step article, I will show you how you can replace the existing templates and how you can send emails by using the replaced templates.
|
||||
|
||||
## Creating the Solution
|
||||
|
||||
Before starting to development, we need to create a solution named `TemplateReplace` (or whatever you want). We can download a new startup template by using [ABP CLI](https://docs.abp.io/en/abp/latest/CLI) :
|
||||
|
||||
````bash
|
||||
abp new TemplateReplace
|
||||
````
|
||||
|
||||
Our project boilerplate will be ready after the download is finished. Then, open the solution in the Visual Studio (or your favorite IDE).
|
||||
|
||||
Run the `TemplateReplace.DbMigrator` application as below to create the database and seed initial data (which creates the admin user, admin role, permissions etc.).
|
||||
|
||||

|
||||
|
||||
* Left click to `TemplateReplace.DbMigrator` and choose the `Debug`.
|
||||
|
||||

|
||||
|
||||
* After that, click the `Start new instance` option to start the database migrations.
|
||||
|
||||

|
||||
|
||||
Then we can run the `TemplateReplace.Web` project to see our application working.
|
||||
|
||||
> _Default login credentials for admin: username is **admin** and password is **1q2w3E\***_
|
||||
|
||||
## Starting the Development
|
||||
|
||||
First thing we need to do is, creating a email service to sending emails. ABP Framework provides `IEmailSender` service that is used to send emails.
|
||||
|
||||
### Step - 1
|
||||
|
||||
Create an `Email` folder in the `TemplateReplace.Application.Contracts` project and add a interface named `IEmailService` inside of it :
|
||||
|
||||
```csharp
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace TemplateReplace.Email
|
||||
{
|
||||
public interface IEmailService
|
||||
{
|
||||
Task<string> SendAsync();
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Step - 2
|
||||
|
||||
Create an `Email` folder in the `TemplateReplace.Application` project and add a class named `EmailService` inside of it to implement the `IEmailService` interface.
|
||||
|
||||
```csharp
|
||||
using System.Threading.Tasks;
|
||||
using Volo.Abp.DependencyInjection;
|
||||
using Volo.Abp.Emailing;
|
||||
using Volo.Abp.Emailing.Templates;
|
||||
using Volo.Abp.TextTemplating;
|
||||
|
||||
namespace TemplateReplace.Email
|
||||
{
|
||||
public class EmailService : IEmailService, ITransientDependency
|
||||
{
|
||||
private readonly IEmailSender _emailSender;
|
||||
private readonly ITemplateRenderer _templateRenderer;
|
||||
|
||||
public EmailService(IEmailSender emailSender, ITemplateRenderer templateRenderer)
|
||||
{
|
||||
_emailSender = emailSender;
|
||||
_templateRenderer = templateRenderer;
|
||||
}
|
||||
|
||||
public async Task<string> SendAsync()
|
||||
{
|
||||
var emailBody = await _templateRenderer.RenderAsync(
|
||||
StandardEmailTemplates.Message,
|
||||
new
|
||||
{
|
||||
message = "This is email body..."
|
||||
}
|
||||
);
|
||||
|
||||
await _emailSender.SendAsync(
|
||||
"from_email@abp.io",
|
||||
"target_email@abp.io",
|
||||
"Subject",
|
||||
emailBody
|
||||
);
|
||||
|
||||
return emailBody;
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
* ABP framework provides a strong and flexible [text templating system](https://docs.abp.io/en/abp/latest/Text-Templating). So, we can use the text templating system to create dynamic email contents.
|
||||
|
||||
* To create an email content, we need to inject `ITemplateRenderer` and use the `RenderAsync` method to render a template.
|
||||
|
||||
* We've used `StandardEmailTemplates.Message` as standart email template. This provides us a standard and simple message template to send mails.
|
||||
|
||||
* The resulting email body should be like shown below:
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<html lang="en" xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
</head>
|
||||
<body>
|
||||
This is email body...
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
### Step - 3
|
||||
|
||||
* Now we need to create a user interface to be able to see the standard email template. To do this quickly, open your existing `Index.cshtml.cs` in your `TemplateReplace.Web` project. It's under the **Pages** folder. And copy-paste the below content.
|
||||
|
||||
```csharp
|
||||
using TemplateReplace.Email;
|
||||
|
||||
namespace TemplateReplace.Web.Pages
|
||||
{
|
||||
public class IndexModel : TemplateReplacePageModel
|
||||
{
|
||||
private readonly IEmailService _emailService;
|
||||
public string EmailBody { get; set; }
|
||||
|
||||
public IndexModel(IEmailService emailService)
|
||||
{
|
||||
_emailService = emailService;
|
||||
}
|
||||
|
||||
public async void OnGet()
|
||||
{
|
||||
if(CurrentUser.IsAuthenticated)
|
||||
{
|
||||
EmailBody = await _emailService.SendAsync();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
* Then, open your `Index.cshtml` file and set the content as below.
|
||||
|
||||
```html
|
||||
@page
|
||||
@using Microsoft.AspNetCore.Mvc.Localization
|
||||
@using TemplateReplace.Localization
|
||||
@using Volo.Abp.Users
|
||||
@model TemplateReplace.Web.Pages.IndexModel
|
||||
@inject IHtmlLocalizer<TemplateReplaceResource> L
|
||||
@inject ICurrentUser CurrentUser
|
||||
@section styles {
|
||||
<abp-style-bundle>
|
||||
<abp-style src="/Pages/Index.css" />
|
||||
</abp-style-bundle>
|
||||
}
|
||||
@section scripts {
|
||||
<abp-script-bundle>
|
||||
<abp-script src="/Pages/Index.js" />
|
||||
</abp-script-bundle>
|
||||
}
|
||||
<div class="jumbotron text-center">
|
||||
<h1>@L["Welcome"]</h1>
|
||||
<div class="row">
|
||||
<div class="col-md-6 mx-auto">
|
||||
<p>@L["LongWelcomeMessage"]</p>
|
||||
<hr class="my-4" />
|
||||
</div>
|
||||
</div>
|
||||
<a href="https://abp.io?ref=tmpl" target="_blank" class="btn btn-primary px-4">abp.io</a>
|
||||
@if (!CurrentUser.IsAuthenticated)
|
||||
{
|
||||
<a abp-button="Primary" href="~/Account/Login" class="px-4"><i class="fa fa-sign-in"></i> @L["Login"]</a>
|
||||
}
|
||||
</div>
|
||||
|
||||
<div class="email-content">
|
||||
@Html.Raw(Model.EmailBody)
|
||||
</div>
|
||||
```
|
||||
|
||||
* After all of this, we can run the `TemplateReplace.Web` application and logged in to see the standard email template.
|
||||
|
||||

|
||||
|
||||
* As we see above, `StandardEmailTemplates.Message` template works as expected. But we need to be sure about the mail has been sent or not. To achieve this, we can examine the **logs**. So, open the `Logs` folder (It's under **TemplateReplace .Web** folder). Inside of this folder, there is a file named `logs.txt`. When we open this file and examine the lines, we can see our email details as below (target email address, subject of mail and email body).
|
||||
|
||||

|
||||
|
||||
### Step - 4
|
||||
|
||||
* So far we've sent mail by using standard email template of ABP. But we can want to replace the email template with the new one. We can achieve this by following [the documentation](https://docs.abp.io/en/abp/latest/Text-Templating#replacing-the-existing-templates).
|
||||
|
||||
* First thing we need to do is creating our new **email template**. So, create a folder named `Templates` and add `EmailLayout.cshtml` file inside of it. And copy-paste the below content.
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<style>
|
||||
a {
|
||||
text-decoration: none !important;
|
||||
}
|
||||
td img {
|
||||
color: #0f3462;
|
||||
}
|
||||
|
||||
table {
|
||||
max-width: 650px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<table border="0" align="center" cellspacing="0" cellpadding="0" bgcolor="white" class="email-template">
|
||||
<tr>
|
||||
<td>
|
||||
<table border="0" cellspacing="0" cellpadding="0" style="color:#0f3462; font-family: sans-serif;">
|
||||
<tr>
|
||||
<td>
|
||||
<h2 style="text-align:center; margin: 0px; padding-bottom: 25px; margin-top: 25px;">
|
||||
<span style="color:lightcoral"></span>
|
||||
</h2>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<img src="https://image.flaticon.com/icons/svg/149/149314.svg" height="90px" style="display:block; margin:auto;padding-bottom: 25px;"/>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="text-align: center;">
|
||||
<h1 style="margin: 0px;padding-bottom: 25px; color: #E90052">ABP Community</h1>
|
||||
<h2 style="margin: 0px;padding-bottom: 25px;font-size:22px;">Share your experiences with the ABP Framework!</h2>
|
||||
<p style=" margin: 0px 40px;padding-bottom: 25px;line-height: 2; font-size: 15px;">
|
||||
ABP is an <a href="https://github.com/abpframework">open source</a> and community driven project. This guide is aims to help anyone wants to contribute to the project.
|
||||
</p>
|
||||
<p style=" margin: 0px 32px;padding-bottom: 25px;line-height: 2; font-size: 15px;">
|
||||
If you want to write articles or "how to" guides related to the ABP Framework and ASP.NET Core, please submit your article to the <a href="https://community.abp.io/">community.abp.io</a> web site.
|
||||
</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<button type="button" style="background-color:#E90052; color:white; padding:15px 97px; outline: none; display: block; margin: auto; border-radius: 31px;
|
||||
font-weight: bold; margin-top: 25px; margin-bottom: 25px; border: none; text-transform:uppercase; ">
|
||||
<a style="text-decoration: none; color:white" href="https://community.abp.io/articles/submit">Contribute</a>
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
<tr style="text-align:center;">
|
||||
<td>
|
||||
<a href="https://github.com/abpframework/abp" style="color: black">
|
||||
<i class="fab fa-github fa-2x" style="padding: 20px"></i>
|
||||
</a>
|
||||
<a href="https://stackoverflow.com/questions/tagged/abp" style="color:orange;">
|
||||
<i style="padding: 20px" class="fab fa-stack-overflow fa-2x"></i>
|
||||
</a>
|
||||
<a href="https://twitter.com/abpframework">
|
||||
<i class="fab fa-twitter fa-2x" style="padding: 20px"></i>
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
* Then we need to make the template file as "Embedded Resource". We can do this as below.
|
||||
|
||||
* First left click to **EmailLayout.cshtml** and choose `Properties`.
|
||||
|
||||

|
||||
|
||||
* Then be sure about build action is **Embedded resource**.
|
||||
|
||||

|
||||
|
||||
### Step - 5 (Replacing the Email Template)
|
||||
|
||||
* To replace the current email template with our new email template, we need to override it. To achieve this, create a class in `TemplateReplace.Web` and fill it with the below content.
|
||||
|
||||
```csharp
|
||||
using Volo.Abp.DependencyInjection;
|
||||
using Volo.Abp.Emailing.Templates;
|
||||
using Volo.Abp.TextTemplating;
|
||||
|
||||
namespace TemplateReplace.Web
|
||||
{
|
||||
public class EmailTemplateDefinitionProvider : TemplateDefinitionProvider, ITransientDependency
|
||||
{
|
||||
public override void Define(ITemplateDefinitionContext context)
|
||||
{
|
||||
var emailLayoutTemplate = context.GetOrNull(StandardEmailTemplates.Message);
|
||||
|
||||
emailLayoutTemplate
|
||||
.WithVirtualFilePath(
|
||||
"/Templates/EmailLayout.cshtml",
|
||||
isInlineLocalized: true
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
* In here we've created a template definition provider class that gets the email layout template and changes the virtual file path for the template.
|
||||
|
||||
* This approach allows us to locate templates in any folder instead of the folder defined by the depended module.
|
||||
|
||||
### Step - 6
|
||||
|
||||
* Lastly, we need to configure the [virtual file system](https://docs.abp.io/en/abp/latest/Virtual-File-System). To do this open your `TemplateReplaceWebModule` in `TemplateReplace.Web` and update the `ConfigureVirtualFileSystem` method as below.
|
||||
|
||||
```csharp
|
||||
//...
|
||||
private void ConfigureVirtualFileSystem(IWebHostEnvironment hostingEnvironment)
|
||||
{
|
||||
if (hostingEnvironment.IsDevelopment())
|
||||
{
|
||||
Configure<AbpVirtualFileSystemOptions>(options =>
|
||||
{
|
||||
options.FileSets.AddEmbedded<TemplateReplaceWebModule>(); //to replace the standard email template
|
||||
|
||||
//...
|
||||
});
|
||||
}
|
||||
}
|
||||
//...
|
||||
```
|
||||
|
||||
* And now when we start the application, we need to see the new email template like as below.
|
||||
|
||||

|
||||
|
||||
## Text Template Management
|
||||
|
||||

|
||||
|
||||
* ABP Commercial's [Text Template Management](https://commercial.abp.io/modules/Volo.TextTemplateManagement) module is really fascinating. It makes it super easy to stores and edits template contents. We can list all templates on a page, editing them, localizing them, and so on.
|
||||
|
||||

|
||||
|
||||
* ABP Commercial's text template management module, allows us to modify a template through the UI.
|
||||
|
||||
* I highly recommend you to [check it out](https://commercial.abp.io/modules/Volo.TextTemplateManagement).
|
||||
|
||||
## References
|
||||
|
||||
* [Text Templating](https://docs.abp.io/en/abp/latest/Text-Templating)
|
||||
* [Emailing](https://docs.abp.io/en/abp/latest/Emailing)
|
||||
* [Virtual File System](https://docs.abp.io/en/abp/latest/Virtual-File-System)
|
||||
|
After Width: | Height: | Size: 43 KiB |
|
After Width: | Height: | Size: 20 KiB |
|
After Width: | Height: | Size: 6.6 KiB |
|
After Width: | Height: | Size: 61 KiB |
|
After Width: | Height: | Size: 100 KiB |
|
After Width: | Height: | Size: 22 KiB |
|
After Width: | Height: | Size: 92 KiB |
|
After Width: | Height: | Size: 65 KiB |
|
After Width: | Height: | Size: 61 KiB |
|
After Width: | Height: | Size: 91 KiB |