Implementing email sending
From this article, you will learn how to send emails from an extension.
Please use the following reference articles to find more details on extensions infrastructure:
Start with a new project
Create a new add-on project as described in the add-on development tutorial.
It can be payment, shipping, customer export, product export and etc extension.
Webstore and Admin mail templates
Sana supports 2 types of mail templates:
- Webstore mail templates, the primary recipients of which are the webstore customers.
- Admin mail templates, the recipients of which are admin users.
The configuration of the mail template will differ depending on who the recipient of the email is.
Webstore mail templates
Adding webstore mail templates
Add a MailTemplates
folder to the root directory of the extension.
Add a MailTemplates.resx
file to this folder.
Create records for email body and subject in the format [templateName]_Body
and [templateName]_Subject
.
Adding views for webstore mail templates
If the body of the letter is simple, the developer of the extension may not add a custom view, so the default one will be used.
Otherwise, the developer can add a custom view to create advanced mail template.
To do this, add the Views
folder to the root directory of the extension.
This folder should contain the _ViewImports.cshtml
file and the MailTemplates
folder.
The MailTemplates
folder should contain main view with name in [templateName].cshtml
format and partial views if needed.
Mail templates directory structure may look like the following:
Sana.Extensions.CustomExtension 📂/
├── MailTemplates 📁/
│ └── MailTemplates.resx
└── Views 📂/
├── MailTemplates 📂/
│ ├── Order 📂/
│ │ └── OrderDetails.cshtml
│ └── FollowEmail.cshtml
└── _ViewImports.cshtml
FollowEmail.cshtml
@model string
@using System.Collections.Specialized
@using Sana.Extensions.Models.Orders
@using System.IO
@using System.Text.Encodings.Web
@{
var orderDetailsModel = (Order)ViewData["OrderDetails"];
async Task<string> PartialToStringAsync(IHtmlHelper<string> html, string viewName, object model)
{
var result = await html.PartialAsync(viewName, model);
using (var writer = new StringWriter())
{
result.WriteTo(writer, HtmlEncoder.Default);
return writer.ToString();
}
}
async Task<NameValueCollection> CreateReplacementTags()
{
var replacementTags = new NameValueCollection();
replacementTags.Add("ORDERDETAILS", await PartialToStringAsync(Html, @"Order\OrderDetails", orderDetailsModel));
return replacementTags;
}
}
<!DOCTYPE HTML PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<head>
<title></title>
</head>
<body style="font-family:Verdana, Arial, Helvetica, sans-serif; font-size: 12px; background-color:White;">
<table cellpadding="0" cellspacing="0" width="700">
<tr>
<td>
@Html.Raw(Model.ReplaceTags(await CreateReplacementTags()))
</td>
</tr>
</table>
</body>
</html>
OrderDetails.cshtml
@model Order
@using Sana.Extensions.Models.Orders
<table>
<tbody>
<tr>
<td>@Extension.SimpleText("OrderId")</td>
<td>@Model.Id</td>
</tr>
<tr>
<td>@Extension.SimpleText("TotalPrice")</td>
<td>@Extension.FormatAsPrice(Model.TotalPrice)</td>
</tr>
</tbody>
</table>
_ViewImports.cshtml
@inject Sana.Extensions.ViewFeatures.IExtensionViewHelper Extension
More details about IExtensionViewHelper can be found in this article.
Implement webstore email sending functionality
An example of a simple implementation of sending webstore email:
var replacementTags = new NameValueCollection();
replacementTags.Add("LINK", "example.com");
Api.MailManager.SendEmail(new List<string>() { "some@sana-commerce.com" }, "FollowEmail", replacementTags);
An example of the advanced implementation of sending webstore email with a partial view for a payment extension:
public override NextAction StartPayment(PaymentStartContext context)
{
...
var replacementTags = new NameValueCollection();
replacementTags.Add("LINK", "example.com");
replacementTags.Add("ORDERDETAILS", "[ORDERDETAILS]");
var additionalData = new Dictionary<string, object>();
additionalData.Add("OrderDetails", context.Order);
Api.MailManager.SendEmail(new[] { some@sana-commerce.com }, "FollowEmail", replacementTags, additionalData);
...
}
Admin mail templates
Adding admin mail templates
Add a AdminMailTemplates
folder to the root directory of the extension.
Add a AdminMailTemplates.resx
file to this folder.
Create records for email body and subject in the format [templateName]_Body
and [templateName]_Subject
.
Adding views for admin mail templates
If the body of the letter is simple, the developer of the extension may not add a custom view, so the default one will be used.
Otherwise, the developer can add a custom view to create advanced mail template.
To do this, add the Views
folder to the root directory of the extension.
This folder should contain the _ViewImports.cshtml
file and the AdminMailTemplates
folder.
The AdminMailTemplates
folder should contain main view with name in [templateName].cshtml
format and partial views if needed.
Mail templates directory structure may look like the following:
Sana.Extensions.CustomExtension 📂/
├── AdminMailTemplates 📁/
│ └── AdminMailTemplates.resx
└── Views 📂/
├── AdminMailTemplates 📂/
│ ├── Order 📂/
│ │ └── OrderDetails.cshtml
│ └── OrderAdminNotification.cshtml
└── _ViewImports.cshtml
OrderAdminNotification.cshtml
@model string
@using System.Collections.Specialized
@using Sana.Extensions.Models.Orders
@using System.IO
@using System.Text.Encodings.Web
@{
var orderDetailsModel = (Order)ViewData["OrderDetails"];
async Task<string> PartialToStringAsync(IHtmlHelper<string> html, string viewName, object model)
{
var result = await html.PartialAsync(viewName, model);
using (var writer = new StringWriter())
{
result.WriteTo(writer, HtmlEncoder.Default);
return writer.ToString();
}
}
async Task<NameValueCollection> CreateReplacementTags()
{
var replacementTags = new NameValueCollection();
replacementTags.Add("ORDERDETAILS", await PartialToStringAsync(Html, @"Order\OrderDetails", orderDetailsModel));
return replacementTags;
}
}
<!DOCTYPE HTML PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<head>
<title></title>
</head>
<body style="font-family:Verdana, Arial, Helvetica, sans-serif; font-size: 12px; background-color:White;">
<table cellpadding="0" cellspacing="0" width="700">
<tr>
<td>
@Html.Raw(Model.ReplaceTags(await CreateReplacementTags()))
</td>
</tr>
</table>
</body>
</html>
OrderDetails.cshtml
@model Order
@using Sana.Extensions.Models.Orders
<table>
<tbody>
<tr>
<td>@Extension.AdminText("OrderId")</td>
<td>@Model.Id</td>
</tr>
<tr>
<td>@Extension.AdminText("TotalPrice")</td>
<td>@Extension.FormatAsPrice(Model.TotalPrice)</td>
</tr>
</tbody>
</table>
_ViewImports.cshtml
@inject Sana.Extensions.ViewFeatures.IExtensionViewHelper Extension
More details about IExtensionViewHelper can be found in this article.
Implement admin email sending functionality
An example of a simple implementation of sending admin email to the customer service email addresses:
var replacementTags = new NameValueCollection();
replacementTags.Add("LINK", "example.com");
Api.MailManager.SendAdminEmailToCustomerService("OrderAdminNotification", replacementTags);
An example of the advanced implementation of sending admin email with a partial view for a payment extension:
public override NextAction StartPayment(PaymentStartContext context)
{
...
var replacementTags = new NameValueCollection();
replacementTags.Add("LINK", "example.com");
replacementTags.Add("ORDERDETAILS", "[ORDERDETAILS]");
var additionalData = new Dictionary<string, object>();
additionalData.Add("OrderDetails", context.Order);
Api.MailManager.SendAdminEmailToCustomerService("OrderAdminNotification", replacementTags, additionalData);
...
}