Join us
@nataliiapolomkina ・ Sep 29,2022 ・ 10 min read ・ 4132 views ・ Originally posted on mailtrap.io
Let’s say you’ve picked Microsoft Azure as a cloud-computing platform for your environment. You may need it for hosting your app, or whatever. At some point, you will need to implement email sending, and this might be troublesome. You can’t send emails directly from any service in Azure. Why? You’ll find the answer below, as well as the details about how to send emails from Azure.
Since November, 15, 2017, Microsoft has banned outbound SMTP communication from Azure computing resources in trial subscriptions.
The restriction applies to unauthenticated email delivery (without SPF, DKIM and DMARC records) via SMTP port 25 through direct DNS MX lookups. The idea is to protect Azure data center IP addresses from reputation abuse. A free account offers $200 credits for 30 days. You can use those to experiment with any service within the Azure platform. With that in mind, users take advantage of this offer for hosting and testing their apps or servers. Isn’t that for what a trial subscription is meant? In practice, those apps/servers send emails without proper sender authentication records. As a result, the reputation of Azure data center public IP addresses drops and they get blacklisted.
The Azure SMTP restriction does not affect enterprise users. Pay-As-You-Go subscribers can unblock the restriction. They need to send a respective support request, which has to be approved by Microsoft.
If you’re a trial subscriber, hold off on switching to AWS or another Azure alternative. You can send emails from Azure but via an SMTP relay service.
To send emails from Azure VMs or Apps, use an authenticated SMTP relay service, also known as a Smart Host, with TLS support.
This is an official recommendation by Microsoft for Azure customers. SMTP relay services provide an intermediary SMTP server between the mail servers of the sender and recipient. The TCP connection is established via the secure ports 587 or 443. However, other SMTP ports may be supported as well.
SendGrid is the most common SMTP relay service to integrate with Microsoft Azure. It allows you to use SendGrid SMTP API (not to be confused with Web or HTTP API) for sending emails. This SMTP relay service is a front-line player in this blog post. We’ll also take a look at such options as Mailjet and Office 365. However, you’re free to pick any authenticated smart host on the market like Elastic Email, SocketLabs, and so on. You can use any of these services without any restriction regardless of your Azure subscription.
SendGrid is a recommended method for sending emails from the Azure function, web job, or any app. SendGrid offers 25K of free emails per month and all sorts of APIs including SMTP, Web, Event, and others. To start using the SMTP relay, you need to create an account and get your SendGrid SMTP credentials. With SMTP API, you’ll need to make a few more manipulations. So, let’s start with the basics.
Click Create once you’re ready.
Now, you have a functioning SMTP relay service, so you can send emails from Azure. And there are a few ways to do this.
Use your SendGrid SMTP server credentials to send emails via PowerShell. Here is a script for a simple text email:
$From = "<user@sender.com>"
$To = "<user@recipient.com>"
$SMTPServer = "smtp.sendgrid.net"
$SMTPPort = "587"
$Username = "<your-SendGrid-username>"
$Password = "<your-SendGrid-password>"
$subject = "Test Email"
$body = "Test email using SendGrid Email Delivery"
$smtp = New-Object System.Net.Mail.SmtpClient($SMTPServer, $SMTPPort)
$smtp.EnableSSL = $true
$smtp.Credentials = New-Object System.Net.NetworkCredential($Username, $Password)
$smtp.Send($From, $To, $subject, $body
Here is the code sample for building a MIME email and sending it through SendGrid:
using System;
using System.Collections.Generic;
using System.Text;
using System.Net.Mail;
using System.Net.Mime;
namespace SmtpMail
{
class Program
{
static void Main()
{
try
{
MailMessage mailMsg = new MailMessage();
mailMsg.To.Add(new MailAddress("user@recipient.com", "The Recipient"));
mailMsg.From = new MailAddress("user@sender.com", "The Sender");
mailMsg.Subject = "Test Email";
string text = "Test Email with SendGrid using .NET's Built-in SMTP Library";
string html = @"<strong>HTML text for the Test Email</strong>";
mailMsg.AlternateViews.Add(AlternateView.CreateAlternateViewFromString(text, null, MediaTypeNames.Text.Plain));
mailMsg.AlternateViews.Add(AlternateView.CreateAlternateViewFromString(html, null, MediaTypeNames.Text.Html));
SmtpClient smtpClient = new SmtpClient("smtp.sendgrid.net", Convert.ToInt32(587));
System.Net.NetworkCredential credentials = new System.Net.NetworkCredential("<SendGrid-username>", "<SendGrid-password>");
smtpClient.Credentials = credentials;
smtpClient.Send(mailMsg);
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
}
}
Install the SendGrid NuGet package in your app. It is a C# client library that will let you use SendGrid APIs to send emails. You can install it right from Visual Studio via Tools => NuGet Package Manager => Manage NuGet Packages for Solution. Browse for SendGrid and install the latest stable version.
Now, check out the following code sample for sending a simple email:
using SendGrid;
using SendGrid.Helpers.Mail;
using System;
using System.Threading.Tasks;
namespace Example
{
internal class Example
{
private static void Main()
{
Execute().Wait();
}
static async Task Execute()
{
var apiKey = Environment.GetEnvironmentVariable("******"); //insert your Sendgrid API Key
var client = new SendGridClient(apiKey);
var from = new EmailAddress("user@sender.com", "The Sender");
var subject = "Test Email with SendGrid";
var to = new EmailAddress("user@recipient.com", "The Recipient");
var plainTextContent = "Test Email with SendGrid C# Library";
var htmlContent = "<strong>HTML text for the Test Email</strong>";
var msg = MailHelper.CreateSingleEmail(from, to, subject, plainTextContent, htmlContent);
var response = await client.SendEmailAsync(msg);
}
}
}
You can also send emails from ASP .NET Core. For this, use the MailHelper class of SendGrid.Helpers.Mail namespace. The API key needs to be stored in the appsettings.json file (you can tweak it from the Azure Portal as well). Here is how it should look:
{
"Logging": {
"IncludeScopes": false,
"LogLevel": {
"Default": "Debug",
"System": "Information",
"Microsoft": "Information"
}
},
"SENDGRID_API_KEY": "*********"
}
To access the API Key from appsettings.json, create the Startup.cs file. Inject the IConfiguration
interface at the constructor of the controller after adding it in the ConfigureServices
method below:
public IConfigurationRoot Configuration { get; }
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc();
services.AddSingleton<IConfiguration>(Configuration);
}
And here is the sample code for the controller:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using SendGrid;
using SendGrid.Helpers.Mail;
using Microsoft.Extensions.Configuration;
namespace SendgridMailApp.Controllers
{
[Route("api/[controller]")]
public class NotificationController : Controller
{
private readonly IConfiguration _configuration;
public NotificationController(IConfiguration configuration)
{
_configuration = configuration;
}
[Route("SendNotification")]
public async Task PostMessage()
{
var apiKey = _configuration.GetSection("SENDGRID_API_KEY").Value;
var client = new SendGridClient(apiKey);
var from = new EmailAddress("user@sender.com", "The Sender");
List<EmailAddress> tos = new List<EmailAddress>
{
new EmailAddress("user1@recipient.com", "The Recipient 1"),
new EmailAddress("user2@recipient.com", "The Recipient 2"),
new EmailAddress("user3@recipient.com", "The Recipient 3")
};
var subject = "Test Email with SendGrid";
var htmlContent = "<strong>HTML text for the Test Email</strong>";
var displayRecipients = false; // set this to true if you want recipients to see each others mail id
var msg = MailHelper.CreateSingleEmailToMultipleRecipients(from, tos, subject, "", htmlContent, false);
await client.SendEmailAsync(msg);
}
}
}
If you want to add an attachment to your email, call the AddAttachment
method and specify the file name and Base64 encoded content. For example:
var attachment = new Attachment()
{
Content = Convert.ToBase64String(raw_content),
Type = "image/png",
Filename = "attachment.png",
Disposition = "inline",
ContentId = "attachment"
};
msg.AddAttachment(attachment);
This requires two steps:
Use the following script to create an Azure KeyVault. Insert your variables and run the code in Azure PowerShell. You can also run the code locally if you have the Azure PowerShell Module installed.
$SubscriptionId = "<subscription ID>"
# Sign in to your Azure account and select your subscription
# If you omit the SubscriptionId parameter, the default subscription is selected.
Connect-AzAccount -SubscriptionId $SubscriptionId
# Use Get-AzLocation to see your available locations.
$region = "southcentralus"
$KeyVaultResourceGroupName = "mykeyvaultgroup"
$VaultName = "<Enter a universally unique vault name>"
$SendGridAPIKey = "<SendGrid API key>"
$AutomationAccountName = "testaa"
# Create new Resource Group, or omit this step if you already have a resource group.
New-AzResourceGroup -Name $KeyVaultResourceGroupName -Location $region
# Create the new key vault
$newKeyVault = New-AzKeyVault -VaultName $VaultName -ResourceGroupName $KeyVaultResourceGroupName -Location $region
$resourceId = $newKeyVault.ResourceId
# Convert the SendGrid API key into a SecureString
$Secret = ConvertTo-SecureString -String $SendGridAPIKey -AsPlainText -Force
Set-AzKeyVaultSecret -VaultName $VaultName -Name 'SendGridAPIKey' -SecretValue $Secret
# Grant access to the KeyVault to the Automation RunAs account.
$connection = Get-AzAutomationConnection -ResourceGroupName $KeyVaultResourceGroupName -AutomationAccountName $AutomationAccountName -Name AzureRunAsConnection
$appID = $connection.FieldDefinitionValues.ApplicationId
Set-AzKeyVaultAccessPolicy -VaultName $VaultName -ServicePrincipalName $appID -PermissionsToSecrets Set, Get
There are other ways to create an Azure KeyVault. Here is one using Portal.
Click Create a Resource and browse “Key Vault”. Click Create.
Fill out the required fields and click Review + Create.
To use Azure KeyVault within a runbook, you need to import Az.Profile and Az.KeyVault modules to your Automation Account. You can do this via PowerShell:
Install-Module -Name Az.Profile
Install-Module -Name Az.KeyVault -RequiredVersion 1.3.1
Or deploy these packages directly to Azure Automation.
Do the following:
Param(
[Parameter(Mandatory=$True)]
[String] $destEmailAddress,
[Parameter(Mandatory=$True)]
[String] $fromEmailAddress,
[Parameter(Mandatory=$True)]
[String] $subject,
[Parameter(Mandatory=$True)]
[String] $content
)
$Conn = Get-AutomationConnection -Name AzureRunAsConnection
Connect-AzAccount -ServicePrincipal -Tenant $Conn.TenantID -ApplicationId $Conn.ApplicationID -CertificateThumbprint $Conn.CertificateThumbprint | Out-Null
$VaultName = "<Enter your vault name>"
$SENDGRID_API_KEY = (Get-AzKeyVaultSecret -VaultName $VaultName -Name "SendGridAPIKey").SecretValueText
$headers = New-Object "System.Collections.Generic.Dictionary[[String],[String]]"
$headers.Add("Authorization", "Bearer " + $SENDGRID_API_KEY)
$headers.Add("Content-Type", "application/json")
$body = @{
personalizations = @(
@{
to = @(
@{
email = $destEmailAddress
}
)
}
)
from = @{
email = $fromEmailAddress
}
subject = $subject
content = @(
@{
type = "text/plain"
value = $content
}
)
}
$bodyJson = $body | ConvertTo-Json -Depth 4
$response = Invoke-RestMethod -Uri https://api.sendgrid.com/v3/mail/send -Method Post -Headers $headers -Body $bodyJson
Similar to SendGrid, Mailjet Email Service is also available on the Azure Marketplace. That’s why, you need to create a Mailjet account and integrate it with Azure. The flow will be almost the same as with SendGrid. The main difference is that Mailjet’s free plan offers only 6K emails compared to SendGrid’s 25K.
Once you’ve seen a Deployment Succeeded pop-up, your Mailjet account has been created but is still in quarantine until you activate it. For this, click Manage, and select Add a Sender Domain or Address in the opened page.
Enter your email address and wait for the confirmation mail. After that, you can send emails from Azure with Mailjet. The required SMTP credentials can be found on the page SMTP and SEND API Settings; your API Key is available on the page Master API Key & Sub API key management.
Similar to SendGrid, you can install the Maijet NuGet package to send emails using the .NET class library via the SMTP API. It contains the following namespaces: Mailjet.Client
and Mailjet.Client.Resources
, which should be declared at the top a C# file.
As for the rest, you can replace SendGrid credentials with those of Mailjet in the code samples above and send emails from Azure with Mailjet. And here is the code sample for building a MIME email and sending it through SendGrid:
using System;
using System.Collections.Generic;
using System.Text;
using System.Net.Mail;
using System.Net.Mime;
namespace SmtpMail
{
class Program
{
static void Main()
{
try
{
MailMessage mailMsg = new MailMessage();
mailMsg.To.Add(new MailAddress("user@recipient.com", "The Recipient"));
mailMsg.From = new MailAddress("user@sender.com", "The Sender");
mailMsg.Subject = "Test Email";
string text = "Test Email with MaiJet using .NET's Built-in SMTP Library";
string html = @"<strong>HTML text for the Test Email</strong>";
mailMsg.AlternateViews.Add(AlternateView.CreateAlternateViewFromString(text, null, MediaTypeNames.Text.Plain));
mailMsg.AlternateViews.Add(AlternateView.CreateAlternateViewFromString(html, null, MediaTypeNames.Text.Html));
SmtpClient smtpClient = new SmtpClient("in-v3.mailjet.com", Convert.ToInt32(587));
System.Net.NetworkCredential credentials = new System.Net.NetworkCredential("<Mailjet-username>", "<Mailjet-password>");
smtpClient.Credentials = credentials;
smtpClient.Send(mailMsg);
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
}
}
If you have an Office 365 subscription, you can use it to send and receive emails from Azure web apps. You’ll need to insert your SMTP server credentials, and employ the System.Net.Mail
class. Check out the following script as an example:
namespace SmtpMail {
class Program {
static void Main() {
MailMessage msg = new MailMessage();
msg.To.Add(new MailAddress("user@recipient.com", "The Recipient"));
msg.From = new MailAddress("user@sender.com", "The Sender");
msg.Subject = "Test Email from Azure Web App using Office365";
msg.Body = "<p>Test emails on Azure from a Web App via Office365</p>";
msg.IsBodyHtml = true;
SmtpClient client = new SmtpClient();
client.UseDefaultCredentials = false;
client.Credentials = new System.Net.NetworkCredential("<Office365-username>", "<Office365-password>");#insert your credentials
client.Port = 587;
client.Host = "smtp.office365.com";
client.DeliveryMethod = SmtpDeliveryMethod.Network;
client.EnableSsl = true;
try {
client.Send(msg);
statusLabel.Text = "Email Successfully Sent";
}
catch(Exception ex) {
statusLabel.Text = ex.ToString();
}
}
}
}
Microsoft Azure provides a connector to Outlook Office 365 in a logic app. This allows you to trigger email delivery from a specific event or action. For example, if an upcoming event in your calendar is starting soon, Azure will send an email. Let’s check out how it works.
You’ll be offered to sign in to Office 365.
The Trigger
The Action
Now, your logic app is saved and automatically enabled.
Some assume that it is possible to use Gmail as a relay server on port 587. However, you won’t be able to send emails from Azure via smtp.gmail.com
on any port. If you try this, you’re likely to get the following error:
[Error] Exception while executing function: Functions.TimerTriggerCSharp1. Microsoft.Azure.WebJobs.Script: One or more errors occurred. System: The SMTP server requires a secure connection or the client was not authenticated. The server response was: 5.5.1 Authentication Required. Learn more at.
or another one:
[Error] Exception while executing function: Functions.TimerTriggerCSharp1. Microsoft.Azure.WebJobs.Script: One or more errors occurred. System: Failure sending mail. System: Unable to read data from the transport connection: net_io_connectionclosed.
Since Azure uses external SMTP relays to send emails, you’ll need to test those. In the blog post, Test SMTP Relay, we described a few tools for that. The testing flow mostly looks as follows:
If the email has been sent, your SMTP server is an open relay and this must be fixed. As an example, let’s test the SendGrid SMTP relay using Mail Server Testing Tool. That’s what we’ve got:
Don’t be confused with the following:
Fail !! smtp.sendgrid.net does not take emails from user@sender.com. Please check your mail server configurations
This means that the SMTP relay works with authenticated senders only, which is fine.
For testing SMTP APIs, you can make use of a dedicated software, such as Fiddler or Postman.
Unfortunately, you can’t use Mailtrap for sending test emails from Azure for now. This is a sad gap by Microsoft because Mailtrap, with its fake SMTP server underneath, can do many things, such as:
Generally, email sending from Azure depends on the third-party SMTP relay service. SendGrid is the most common and recommended solution for that. You can find many examples and docs on how to integrate Azure and SendGrid and send emails. At the same time, you can opt for another solution supporting SMTP relay: Mailjet, SocketLabs, Elastic Email, and so on. Sending emails with Office 365 is also possible, though it’s mostly used for logic apps.
Thanks for reading our guide on how to send emails using Azure, which was originally published in the Mailtrap blog by Dmitriy Shcherbakan.
Join other developers and claim your FAUN account now!
Influence
Total Hits
Posts
Only registered users can post comments. Please, login or signup.