@ -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 |