Guidance for configuring and sending emails in Orchard Core using the OrchardCore.Email module, including SMTP setup, programmatic sending via ISmtpService, Liquid-based email templates, recipe-driven configuration, workflow email activities, and the Azure Communication Services email provider.
OrchardCore.Email supplies the provider-neutral email API. Enable an email
provider and configure one enabled provider as the default before application
code sends mail.
| Provider module | Tenant provider technical name | Configuration-backed default |
|---|---|---|
| OrchardCore.Email.Smtp | SMTP | DefaultSMTP |
| OrchardCore.Email.Azure | Azure | DefaultAzure |
The email settings page is Settings → Communication → Email. It lists
enabled providers and selects EmailSettings.DefaultProviderName. Enabling the
last valid tenant provider selects it automatically; otherwise explicitly
choose the default. The test page is Tools → Testing → Email Test and lets
an administrator select an enabled provider for the test message.
{
"steps": [
{
"name": "Feature",
"enable": [
"OrchardCore.Email",
"OrchardCore.Email.Smtp"
]
},
{
"name": "Settings",
"SmtpSettings": {
"IsEnabled": true,
"DefaultSender": "noreply@example.com",
"Host": "smtp.example.com",
"Port": 587,
"AutoSelectEncryption": false,
"EncryptionMethod": "STARTTLS",
"RequireCredentials": true,
"UserName": "smtp-user",
"Password": "use-a-secret-provider",
"DeliveryMethod": "Network"
},
"EmailSettings": {
"DefaultProviderName": "SMTP"
}
}
]
}
OrchardCore_Email_Smtp configures the DefaultSMTP provider. Use the
settings UI for a tenant-specific SMTP provider. Do not commit credentials.
{
"steps": [
{
"name": "Feature",
"enable": [
"OrchardCore.Email",
"OrchardCore.Email.Azure"
]
},
{
"name": "Settings",
"AzureEmailSettings": {
"IsEnabled": true,
"DefaultSender": "DoNotReply@your-domain.azurecomm.net",
"ConnectionString": "supply-from-a-secure-source"
},
"EmailSettings": {
"DefaultProviderName": "Azure"
}
}
]
}
OrchardCore_Email_AzureCommunicationServices configures DefaultAzure.
Use a verified ACS sender and secure configuration for connection strings.
Inject IEmailService; ISmtpService, SmtpResult, and
MailKitSmtpService are not the v3 API. Use HtmlBody and/or TextBody;
Body and IsHtmlBody are obsolete.
using OrchardCore.Email;
using OrchardCore.Infrastructure;
namespace MyModule;
public sealed class OrderConfirmationService
{
private readonly IEmailService _emailService;
public OrderConfirmationService(IEmailService emailService)
{
_emailService = emailService;
}
public Task<Result> SendAsync(
string recipientEmail,
string orderId,
CancellationToken cancellationToken = default)
{
var message = new MailMessage
{
To = recipientEmail,
Subject = $"Order confirmation {orderId}",
HtmlBody = $"<p>Your order <strong>{orderId}</strong> has been confirmed.</p>",
TextBody = $"Your order {orderId} has been confirmed.",
};
return _emailService.SendAsync(message, cancellationToken: cancellationToken);
}
}
Pass a provider technical name only when deliberately overriding the configured default:
var result = await _emailService.SendAsync(
message,
providerName: "SMTP",
cancellationToken: cancellationToken);
if (!result.Succeeded)
{
foreach (var error in result.Errors)
{
logger.LogError("Email send failed: {Error}", error.Message.Value);
}
}
MailMessage supports From, To, Cc, Bcc, ReplyTo, Sender,
Subject, HtmlBody, TextBody, and Attachments.
IEmailService.SendAsync() and IEmailProvider.SendAsync() accept a
CancellationToken. Pass the request token through custom providers and
event handlers so shutdown and request cancellation can stop delivery.
Render a Liquid template before assigning it to HtmlBody:
var html = await _liquidTemplateManager.RenderStringAsync(
"<p>Welcome, {{ UserName }}!</p>",
System.Text.Encodings.Web.HtmlEncoder.Default,
new { UserName = userName });
await _emailService.SendAsync(new MailMessage
{
To = recipientEmail,
Subject = "Welcome",
HtmlBody = html,
TextBody = $"Welcome, {userName}!",
});
Implement IEmailServiceEvents, or derive from EmailServiceEventsBase, to
observe validation and delivery. Event methods receive a cancellation token;
ValidatedAsync and ValidatingAsync also receive
MailMessageValidationContext.
using OrchardCore.Email;
using OrchardCore.Email.Services;
namespace MyModule;
public sealed class EmailAuditHandler : EmailServiceEventsBase
{
private readonly ILogger<EmailAuditHandler> _logger;
public EmailAuditHandler(ILogger<EmailAuditHandler> logger)
{
_logger = logger;
}
public override Task SendingAsync(MailMessage message, CancellationToken cancellationToken = default)
{
_logger.LogInformation("Sending email with subject {Subject}.", message.Subject);
return Task.CompletedTask;
}
public override Task FailedAsync(MailMessage message, CancellationToken cancellationToken = default)
{
_logger.LogWarning("Email delivery failed for subject {Subject}.", message.Subject);
return Task.CompletedTask;
}
}
Register the handler as IEmailServiceEvents.
services.AddScoped<IEmailServiceEvents, EmailAuditHandler>();
With OrchardCore.Email and OrchardCore.Workflows enabled, use the Send
Email workflow activity. Its body is rendered as HTML, so provide HTML there
and keep provider configuration outside the workflow definition.
Search for places (restaurants, cafes, etc.) via Google Places API proxy on localhost.
Interact with GitHub using the `gh` CLI. Use `gh issue`, `gh pr`, `gh run`, and `gh api` for issues, PRs, CI runs, and advanced queries.
Create or update AgentSkills. Use when designing, structuring, or packaging skills with scripts, references, and assets.
Start voice calls via the OpenClaw voice-call plugin.
Notion API for creating and managing pages, databases, and blocks.
Gemini CLI for one-shot Q&A, summaries, and generation.
Category:developer