Files
mixtape/Finch/Mails/Dispatchers/Scaleway/ScalewayDispatcher.cs
T

210 lines
5.5 KiB
C#

using System.IO;
using System.Net.Http;
using System.Net.Http.Json;
using System.Net.Mail;
using System.Text.Json;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Attachment = System.Net.Mail.Attachment;
namespace Finch.Mails.Dispatchers.Scaleway;
public class ScalewayDispatcher : IMailDispatcher
{
/// <inheritdoc />
public int Priority { get; } = 3;
protected Queue<Mail> Queue { get; } = new();
protected MailOptions Options { get; set; }
protected IWebHostEnvironment Env { get; set; }
protected HttpClient Http { get; }
protected JsonSerializerOptions JsonSerializerOptions { get; }
protected ILogger<ScalewayDispatcher> Logger { get; }
public ScalewayDispatcher(IOptionsMonitor<MailOptions> monitor, IWebHostEnvironment env, HttpClient http, ILogger<ScalewayDispatcher> logger)
{
Options = monitor.CurrentValue;
Env = env;
Http = http;
Http.DefaultRequestHeaders.Add("X-Auth-Token", Options.Scaleway.SecretKey);
JsonSerializerOptions = new JsonSerializerOptions
{
PropertyNamingPolicy = JsonNamingPolicy.SnakeCaseLower
};
Logger = logger;
monitor.OnChange(opts => Options = opts);
}
/// <inheritdoc />
public bool CanSend()
{
return Options.Scaleway != null && !Options.Scaleway.ProjectId.IsNullOrEmpty() && !Options.Scaleway.SecretKey.IsNullOrEmpty();
}
/// <inheritdoc />
public async Task<bool> IsSenderSupported(string email, CancellationToken token = default)
{
if (email.IsNullOrWhiteSpace())
{
return true;
}
try
{
string domain = email.FullTrim().Split('@').LastOrDefault();
string uri = Options.Scaleway.ApiUrl + $"/transactional-email/v1alpha1/regions/{Options.Scaleway.Region}/domains?project_id={Options.Scaleway.ProjectId}&status=checked";
ScalewayResponse.ListDomains response = await Http.GetFromJsonAsync<ScalewayResponse.ListDomains>(uri, JsonSerializerOptions, token);
return response.Domains.Any(x => x.Name.Equals(domain, StringComparison.InvariantCultureIgnoreCase));
}
catch
{
return true;
}
}
/// <inheritdoc />
public async Task Send(Mail message, CancellationToken token = default)
{
string uri = Options.Scaleway.ApiUrl + $"/transactional-email/v1alpha1/regions/{Options.Scaleway.Region}/emails";
ScalewayRequest.SendEmail data = new()
{
// to addresses
To = Convert(message.To),
Cc = Convert(message.CC),
Bcc = Convert(message.Bcc),
// from address
From = new ScalewayRequest.EmailAddress()
{
Email = message.From!.Address,
Name = message.From.DisplayName
},
// subject
Subject = message.Subject
};
// add reply-to header
if (message.ReplyToList.Any())
{
data.AdditionalHeaders.Add(new()
{
Key = "Reply-To",
Value = message.ReplyToList.ToString()
});
}
// add additional headers
if (message.Metadata.Any())
{
foreach (KeyValuePair<string, string> item in message.Metadata)
{
data.AdditionalHeaders.Add(new()
{
Key = item.Key,
Value = item.Value
});
}
}
// set attachments
foreach (Attachment attachment in message.Attachments)
{
data.Attachments.Add(Convert(attachment));
}
// set body
if (!message.IsBodyHtml)
{
data.Text = message.Body;
}
else
{
data.Html = message.Body;
}
// overwrite for debug mode
if (Options.Debug || (Env != null && !Env.IsProduction()))
{
data.From = new ScalewayRequest.EmailAddress()
{
Email = "noreply@post.swcs.pro"
};
data.Cc = null; // "cee-maildev@gmx.at,anaheimcore@gmail.com,ceemaildev@yahoo.com";
data.Bcc = null;
data.To = [new ScalewayRequest.EmailAddress()
{
Email = "maildev@alias.swcs.pro"
}];
data.Subject = $"{data.Subject} (test)";
}
try
{
using HttpResponseMessage responseMessage = await Http.PostAsJsonAsync(uri, data, JsonSerializerOptions, token);
ScalewayResponse.Email response = await responseMessage.Content.ReadFromJsonAsync<ScalewayResponse.Email>(JsonSerializerOptions, token);
Logger.LogDebug("Email {id} sent via Scaleway API with status {status}", response.Id, response.Status);
}
catch (Exception ex)
{
Logger.LogError(ex, "Could not send message via Scaleway API");
}
}
/// <inheritdoc />
public void Dispose() { }
/// <summary>
/// Convert a collection of addresses to a scaleway email addresses
/// </summary>
protected List<ScalewayRequest.EmailAddress> Convert(MailAddressCollection addresses)
{
return addresses
.Select(address => new ScalewayRequest.EmailAddress()
{
Email = address.Address,
Name = address.DisplayName
})
.ToList();
}
/// <summary>
/// Convert an attachment to a scaleway email attachment
/// </summary>
protected ScalewayRequest.EmailAttachment Convert(Attachment attachment)
{
byte[] buffer = new byte[8067];
using MemoryStream memoryStream = new();
int count;
while ((count = attachment.ContentStream.Read(buffer, 0, buffer.Length)) > 0)
{
memoryStream.Write(buffer, 0, count);
}
string base64String = System.Convert.ToBase64String(memoryStream.ToArray());
return new()
{
Name = attachment.Name,
Type = attachment.ContentType.MediaType,
Content = base64String
};
}
}