This post is part of series starting here.
Here’s how I configure my mailers in a ASP.Net Core project developed in F#. I define an interface:
type IMailer =
// to * subject * body
abstract Send: string * string * string -> unit
of which I have 2 implementation. The first one is for development as it simply prints the mail on the server’s standard output:
type ConsoleMailer() =
interface IMailer with
member _.Send(recipient, subject, body) =
printfn "Sending mail:\nTo:%s\nSubject:%s\n%s" recipient subject body
The second implementation is for production:
open MailKit.Net.Smtp
open MailKit
open MimeKit
type ProductionMailer(host:string, port:int, login:string,password:string) =
interface IMailer with
member _.Send(recipient, subject, body) =
let message = new MimeMessage()
message.From.Add (new MailboxAddress ("ProjectName", "info@example.com"))
message.To.Add (new MailboxAddress ("", recipient));
message.Subject <- subject
message.Body <- new TextPart("plain",Text=body)
try
let client = new SmtpClient()
client.Connect(host,port,true)
client.Authenticate(login,password)
client.Send(message)|> ignore
client.Disconnect(true)
with e ->
printfn "Exception: %A" e
and its config is set in a JSON file handled by this code:
open FSharp.Data
type MailConfig = JsonProvider<"config/mail.json.sample", EmbeddedResource="lib, lib.embedded.mail.json.sample">
It uses a type provider using the project’s provided sample config file, which is
{
"host":"mail.example.com",
"port": 25,
"login": "username",
"password": "superpass"
}
With all building block available, we can then inject them in the application in the Startup
class' ConfigureServices
method.
if env.IsDevelopment() then
services.AddTransient<IMailer,ConsoleMailer>() |> ignore
else
let mailConfigFile = Environment.GetEnvironmentVariable("WADESDA_MAIL_CONFIG_FILE")
if not (isNull mailConfigFile) && System.IO.File.Exists(mailConfigFile) then
let mailConfig = MailConfig.Load(mailConfigFile)
let mailer =
ProductionMailer(mailConfig.Host,
mailConfig.Port,
mailConfig.Login,
mailConfig.Password
)
services.AddTransient<IMailer>(fun s -> mailer :> IMailer) |> ignore
We inject the dependency as transient so that every request for an instance gets a new one. And that’s it. In the app, you fist need to get a handle on the mailer. In WebSharper, you do it like this:
let httpContext:Microsoft.AspNetCore.Http.HttpContext = ctx.HttpContext()
let serviceProvider= httpContext.RequestServices
let mailer = serviceProvider.GetService(typeof<IMailer>)
Sending a mail is then done like this:
mailer.Send(emailAddress,subject, body)