In this post, let's see how to send emails using Azure Communication Services (ACS) in a .NET application. With SendGrid's free tier being discontinued, ACS has become an attractive alternative for sending transactional emails from Azure-hosted applications.
- Email Communication Services - This handles email domain configuration
- Communication Services - This is the main resource your application connects to
- Azure Managed Domain: Quick setup, gives you a subdomain like DoNotReply@xxxxxxxx.azurecomm.net
- Custom Domain: Use your own domain like noreply@yourdomain.com
For a custom domain, you'll need to add following DNS records for verification, Azure will provide the values.
- TXT: Domain ownership verification
- TXT: SPF (Sender Policy Framework)
- CNAME: DKIM key 1
- CNAME: DKIM key 2
You can do this by clicking on
Provision domains -> Custom domain and following the steps.
|
|
| Email Communication Services: Add Custom Domain |
v=spf1 include:spf.protection.outlook.com include:other.service.com -all
|
|
| Email Communication Services Domain: MainFrom addresses |
Linking Domain to Communication Services
Create a Communication Services resource, then navigate to Email -> Domains -> Connect domains and link your verified domain.
First we need install the following NuGet Package.
dotnet add package Azure.Communication.Email
Add the following to your appsettings.json:
{
"Email": {
"Endpoint": "https://<your-acs-resource>.communication.azure.com",
"SenderAddress": "<configured_mailfrom_address>"
}
}
We can define an Options Class to map Email settings.
namespace YourApp.Options; public record Email { public required string Endpoint { get; init; } public required string SenderAddress { get; init; } }
Now let's register the Email options, EmailClient and an EmailService.
// In Program.cs
builder.Services.AddOptions<Email>()
.Bind(builder.Configuration.GetSection("Email"));
builder.Services.AddSingleton<EmailClient>(sp =>
{
var emailOptions = sp.GetRequiredService<IOptions<Email>>();
var credential = new DefaultAzureCredential();
return new EmailClient(new Uri(emailOptions.Value.Endpoint), credential);
});
builder.Services.AddScoped<EmailService>();
Now let's create a simple EmailService.
using Azure.Communication.Email; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; namespace YourApp.Services; public class EmailService { private readonly EmailClient _emailClient; private readonly Email _emailOptions; private readonly ILogger<EmailService> _logger; public EmailService( EmailClient emailClient, IOptions<Email> emailOptions, ILogger<EmailService> logger) { _emailClient = emailClient; _emailOptions = emailOptions.Value; _logger = logger; } public async Task SendEmailAsync( string recipientEmail, string subject, string htmlContent, string plainTextContent, CancellationToken cancellationToken = default) { var emailMessage = new EmailMessage( senderAddress: _emailOptions.SenderAddress, recipientAddress: recipientEmail, content: new EmailContent(subject) { Html = htmlContent, PlainText = plainTextContent }); try { EmailSendOperation operation = await _emailClient.SendAsync( Azure.WaitUntil.Completed, emailMessage, cancellationToken); _logger.LogInformation( "Email sent successfully. MessageId: {MessageId}", operation.Id); } catch (Exception ex) { _logger.LogError(ex, "Failed to send email"); throw; } } }
Managed Identity RBAC Role
When using DefaultAzureCredential with an Managed Identity in Production, you must assign the Communication and Email Service Owner RBAC role to your identity on the Communication Services resource.
az role assignment create `
--assignee <managed-identity-principal-id> `
--role "Communication and Email Service Owner" `
--scope /subscriptions/<subscriptionId>/resourceGroups/<resourceGroup>/providers/Microsoft.Communication/CommunicationServices/<acsName>
Once email is sent:
|
|
| Received Email |
Hope this helps.
More read:
Azure Communication Services Email Overview
Quickstart: Send Email
Email Pricing
Happy Coding.
Regards,
Jaliya
No comments:
Post a Comment