diff --git a/src/Email/Email.csproj b/src/Email/Email.csproj index bc6e803d130e9233679f65ccd356f6d12704d584..ac9f5d9abfdd66d7e35804a5729f5e3d5d3afe37 100644 --- a/src/Email/Email.csproj +++ b/src/Email/Email.csproj @@ -15,4 +15,7 @@ <PackageProjectUrl>https://git.rwth-aachen.de/coscine/backend/libraries/Email</PackageProjectUrl> <PackageRequireLicenseAcceptance>false</PackageRequireLicenseAcceptance> </PropertyGroup> + <ItemGroup> + <PackageReference Include="MailKit" Version="3.0.0-preview1" /> + </ItemGroup> </Project> \ No newline at end of file diff --git a/src/Email/SignedEmail.cs b/src/Email/SignedEmail.cs new file mode 100644 index 0000000000000000000000000000000000000000..07690df064f3f9970f8f8ab5f06517a98cac6dde --- /dev/null +++ b/src/Email/SignedEmail.cs @@ -0,0 +1,109 @@ +using MailKit.Net.Smtp; +using MimeKit; +using MimeKit.Cryptography; +using System; +using System.IO; +using System.Security.Cryptography.X509Certificates; +using System.Threading.Tasks; + +namespace Coscine.Email +{ + public class SignedEmail : IEmail, IDisposable + { + private readonly SmtpClient _client; + private readonly string _certificatePath; + private readonly string _certificatePassword; + + public SignedEmail(string certificatePath, string certificatePassword, string host) + { + _certificatePath = certificatePath; + _certificatePassword = certificatePassword; + + _client = new SmtpClient(); + _client.Connect(host, 25, false); + } + + + public bool SendEmail(string from, string to, string cc, string mailSubject, Stream content) + { + return SendEmail(from, to, cc, mailSubject, StreamToString(content)); + } + + public bool SendEmail(string from, string to, string cc, string mailSubject, string content) + { + try + { + MimeMessage message = CreateMailMessage(from, to, cc, mailSubject); + message = SignMailMessage(message, content, _certificatePath, _certificatePassword); + + _client.Send(message); + + return true; + } + catch (Exception) + { + return false; + } + } + + public async Task SendEmailAsync(string from, string to, string cc, string mailSubject, Stream content) + { + await SendEmailAsync(from, to, cc, mailSubject, StreamToString(content)); + } + + public async Task SendEmailAsync(string from, string to, string cc, string mailSubject, string content) + { + MimeMessage message = CreateMailMessage(from, to, cc, mailSubject); + message = SignMailMessage(message, content, _certificatePath, _certificatePassword); + + await _client.SendAsync(message); + } + + private static string StreamToString(Stream content) + { + string s; + using (var sr = new StreamReader(content)) + { + s = sr.ReadToEnd(); + } + return s; + } + + private static MimeMessage CreateMailMessage(string from, string to, string cc, string mailSubject) + { + MimeMessage message = new MimeMessage(); + message.From.Add(new MailboxAddress(from, from)); + message.To.Add(new MailboxAddress(to, to)); + message.Subject = mailSubject; + if (!string.IsNullOrEmpty(cc)) + { + message.Cc.Add(new MailboxAddress(cc, cc)); + } + + return message; + } + + private static MimeMessage SignMailMessage(MimeMessage message, string content, string certificatePath, string certificatePassword) + { + var body = new TextPart("html") + { + Text = content + }; + + var certificate = new X509Certificate2(certificatePath, certificatePassword, X509KeyStorageFlags.Exportable); + + using (var ctx = new TemporarySecureMimeContext()) + { + CmsSigner signer = new CmsSigner(certificate); + message.Body = ApplicationPkcs7Mime.Sign(ctx, signer, body); + } + + return message; + } + + public void Dispose() + { + _client.Dispose(); + } + } +}