CMS 12 send email - The SMTP host was not specified

Vote:
 

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?

#310350
Edited, Oct 10, 2023 15:01
Vote:
 

Code looks ok but I believe the default appsetting name is SmtpOptions and not smtp. Could you try it out.

#310352
Oct 10, 2023 19:03
Vote:
 

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);
    }
}
#310618
Oct 11, 2023 6:48
Vote:
 

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.

#310625
Edited, Oct 11, 2023 12:44
Vote:
 

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.

#310633
Oct 11, 2023 15:18
Vote:
 

Hi Mike

You could also go API instead of SMTP, as proposed here. More modern.

#310673
Oct 12, 2023 4:45
Vote:
 

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);
}
#310691
Oct 12, 2023 12:14
This topic was created over six months ago and has been resolved. If you have a similar question, please create a new topic and refer to this one.
* You are NOT allowed to include any hyperlinks in the post because your account hasn't associated to your company. User profile should be updated.