November Happy Hour will be moved to Thursday December 5th.
November Happy Hour will be moved to Thursday December 5th.
Code looks ok but I believe the default appsetting name is SmtpOptions and not smtp. Could you try it out.
I tried with SmtpOptions and got the same error.
These two sites have 'Smtp'
https://docs.developers.optimizely.com/content-management-system/docs/configuring-your-email-server
https://docs.developers.optimizely.com/digital-experience-platform/docs/configuring-the-email-server
It took me some trial and error before getting this to work, and this is how we have set it up in one of our projects. In the `startup.cs` this is added:
Setting up SmtpOptions. You will need to call ConfigureSmttp(..) of course from elsewhere in startup.cs.
private void ConfigureSmtp(IServiceCollection services)
{
services.Configure<SmtpOptions>(x =>
{
x.DeliveryMethod = DeliveryMethod.Network;
x.Network = new Network
{
UserName = _configuration.GetValue<string>("EPiServer:Cms:Smtp:Network:UserName"),
Password = _configuration.GetValue<string>("EPiServer:Cms:Smtp:Network:Password"),
UseSsl = true,
Port = _configuration.GetValue<int>("EPiServer:Cms:Smtp:Network:Port"),
Host = _configuration.GetValue<string>("EPiServer:Cms:Smtp:Network:Host"),
};
});
services.AddScoped<SmtpClient>((serviceProvider) =>
{
var config = serviceProvider.GetRequiredService<IConfiguration>();
return new SmtpClient
{
Host = _configuration.GetValue<string>("EPiServer:Cms:Smtp:Network:Host"),
Port = _configuration.GetValue<int>("EPiServer:Cms:Smtp:Network:Port"),
EnableSsl = true,
Credentials = new NetworkCredential(
config.GetValue<String>("EPiServer:Cms:Smtp:Network:UserName"),
_configuration.GetValue<string>("EPiServer:Cms:Smtp:Network:Password")
)
};
});
}
When Optimizely sends an email after form-submission, the platform uses MimeKit and not SmtpClient. The code below has two samples showing how to call it (code here, is in a controller).
For testing:
using System.Net.Mail;
using EPiServer.Framework;
using EPiServer.Notification.Internal;
using EPiServer.Web.Mvc;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using MimeKit;
namespace Website.Features.Test;
[Authorize(Roles = "CmsAdmins")]
public class MyPageController : PageController<MyPage>
{
private readonly ILogger<MyPageController> _logger;
private readonly SmtpClient _smtpClient;
private readonly ISmtpClient _ismtpClient;
public MyPageController(
ILogger<MyPageController> logger,
SmtpClient smtpClient,
ISmtpClient ismtpClient)
{
_logger = logger;
_smtpClient = smtpClient;
_ismtpClient = ismtpClient;
}
public async Task<ActionResult> SendMail(MyPage currentPage, string? to, string? subject)
{
if (string.IsNullOrEmpty(to))
return BadRequest("Missing to, such as: www..../SendEmail?to=test@test.com");
var message = new MailMessage
(new MailAddress("noreply@xxx.xxx"), // from
new MailAddress(to) // to
)
{
Subject = subject ?? "Test email, " + DateTime.UtcNow.ToString("yyyy-MM-ddTHH:mm:ss"),
Body = "Test email, " + DateTime.UtcNow.ToString("yyyy-MM-ddTHH:mm:ss")
};
await _smtpClient.SendMailAsync(message);
return Ok("Mail sent to: " + to);
}
public async Task<ActionResult> SendMail2(MyPage currentPage, string? to, string? subject)
{
_logger.LogWarning("SendMail2 called: ");
if (string.IsNullOrEmpty(to))
return BadRequest("Missing to, such as: www..../SendMail2?to=test@test.com");
MimeMessage message = new MimeMessage();
message.From.Add(InternetAddress.Parse("no-reply@xxx.xxx"));
message.To.Add(InternetAddress.Parse(to));
message.Subject = subject ?? "Test emai, " + DateTime.UtcNow.ToString("yyyy-MM-ddTHH:mm:ss");
message.Body = new TextPart("html")
{
Text = "Test email, " + DateTime.UtcNow.ToString("yyyy-MM-ddTHH:mm:ss")
};
await _ismtpClient.SendAsync(message);
return Ok("Mail sent to: " + to);
}
}
In my project I only used appSettings to setup the SmtpOptions like this:
"EPiServer": {
"Cms": {
"SmtpOptions": {
"Network": {
"Host": "smtp.sendgrid.net",
"Port": "587",
"UserName": "apikey",
"Password": "ABCDEFG",
"UseSsl": true
}
}
},
Then for this example I simplified our "MailService" which we use to send emails.
using System;
using System.Net;
using System.Net.Mail;
using EPiServer.Framework;
using EPiServer.ServiceLocation;
using Microsoft.Extensions.Logging;
public class MailService : IMailService
{
private static readonly ILogger<MailService> Log = ServiceLocator.Current.GetInstance<ILogger<MailService>>();
private readonly SmtpOptions smtpOptions;
public MailService(SmtpOptions smtpOptions)
{
this.smtpOptions = smtpOptions;
}
public void Send(MailMessage mailMessage)
{
using var client = new SmtpClient
{
Host = this.smtpOptions.Network.Host,
Port = this.smtpOptions.Network.Port.GetValueOrDefault(),
EnableSsl = this.smtpOptions.Network.UseSsl.GetValueOrDefault(),
Credentials = new NetworkCredential(this.smtpOptions.Network.UserName, this.smtpOptions.Network.Password),
};
try
{
client.Send(mailMessage);
}
catch (Exception exception)
{
Log.LogError(exception, "Error when sending Email.");
}
}
}
As you can see in our constructor for MailService we inject SmtpOptions which is the EPiServer.Framework class that holds the specified options from your appSettings in this example.
So we map our specified SmtpOptions to our SmtpClient and it works.
I had problem initially when I used Smtp instead of SmtpOptions in my appsettings.
Hope this can help.
If you're able to replace SmtpClient with MimeKit, I would recommend it. Episerver has some internal classes to support their configuration options and handling for SpecifiedPickupDirectory, which can be accessed from EPiServer.Notification.Internal.ISmtpClient, although be aware that it could change in future update without notice.
Hi Mike
You could also go API instead of SMTP, as proposed here. More modern.
I got it to work doing the following...
I did this in Startup.cs
services.AddTransient<SmtpClient>((serviceProvider) =>
{
return new SmtpClient
{
Host = _configuration.GetValue<string>("EPiServer:Cms:Smtp:Network:Host"),
Port = _configuration.GetValue<int>("EPiServer:Cms:Smtp:Network:Port"),
EnableSsl = true,
Credentials = new NetworkCredential(
_configuration.GetValue<String>("EPiServer:Cms:Smtp:Network:UserName"),
_configuration.GetValue<string>("EPiServer:Cms:Smtp:Network:Password")
)
};
});
then I did this to send my email
private Injected<IHttpContextAccessor> _contextAccessor;
using (var client = _contextAccessor.Service.HttpContext.RequestServices.GetRequiredService<SmtpClient>())
{
MailMessage mail = new MailMessage();
mail.From = new MailAddress(Shared.Properties.Settings.Default.SentFromEmail);
mail.To.Add(email);
mail.Body = emailBody.ToString();
mail.IsBodyHtml = true;
mail.Subject = $"Ready to Publish - {e.Content.Name}";
client.Send(mail);
}
I have the Smtp section defined in appsettings.json
When I try calling client.Send() I receive the error: The SMTP host was not specified
Is there additional configuration required to send email using SmtpClient?