193 lines
7.1 KiB
C#
193 lines
7.1 KiB
C#
using MailKit.Net.Smtp;
|
|
using MailKit.Security;
|
|
using MimeKit;
|
|
using Sarand.Net.Standard.Base.App;
|
|
using Sarand.Net.Standard.Base.Core;
|
|
using Sarand.Net.Standard.Base.Utils;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.IO;
|
|
using System.Text;
|
|
using System.Text.RegularExpressions;
|
|
|
|
namespace Sarand.Net.Standard.Base.Email
|
|
{
|
|
//=======================================================================
|
|
public abstract class SaEmailConsole
|
|
{
|
|
//-------------------------------------------------------------------
|
|
// Protected construction.
|
|
protected SaEmailConsole()
|
|
{
|
|
}
|
|
|
|
//-------------------------------------------------------------------
|
|
// Send email.
|
|
//-------------------------------------------------------------------
|
|
public bool SendEmail(SaEmailData emailData)
|
|
{
|
|
// Validate email data.
|
|
if (emailData.AddressesTo.IsEmpty())
|
|
{
|
|
SaLogger.Error($"{SysUtil.Fn} Unable to send email - To address not specified.");
|
|
return false;
|
|
}
|
|
|
|
try
|
|
{
|
|
// Mail message.
|
|
MimeMessage mailMessage = CreateMailMessage(emailData);
|
|
|
|
// Send the email.
|
|
using (var smtpClient = new SmtpClient())
|
|
{
|
|
smtpClient.ServerCertificateValidationCallback = (s, c, h, e) => true;
|
|
|
|
smtpClient.Connect(emailData.Config.SMTP.Server, emailData.Config.SMTP.ServerPort, emailData.Config.SMTP.UseSSL ? SecureSocketOptions.StartTlsWhenAvailable : SecureSocketOptions.Auto);
|
|
if (!StringUtil.IsEmpty(emailData.Config.Send.UserName))
|
|
smtpClient.Authenticate(emailData.Config.Send.UserName, emailData.Config.Send.Password);
|
|
smtpClient.Send(mailMessage);
|
|
smtpClient.Disconnect(true);
|
|
}
|
|
}
|
|
catch (Exception exc)
|
|
{
|
|
SaLogger.Error($"{SysUtil.Fn} {ExceptionUtil.GetLogMessage(exc)}");
|
|
return false;
|
|
}
|
|
SaLogger.Info($"{SysUtil.Fn} Email sent to {emailData.AddressesTo[0]}. Subject: {emailData.Subject}");
|
|
return true;
|
|
}
|
|
|
|
//-------------------------------------------------------------------
|
|
private MimeMessage CreateMailMessage(SaEmailData emailData)
|
|
{
|
|
// Mail message.
|
|
MimeMessage mailMessage = new MimeMessage();
|
|
|
|
// Addresses.
|
|
mailMessage.From.Add(new MailboxAddress("", emailData.Config.Message.AddressFrom));
|
|
foreach (String addressTo in emailData.AddressesTo)
|
|
mailMessage.To.Add(new MailboxAddress("", addressTo));
|
|
foreach (String addressCc in emailData.AddressesCc)
|
|
mailMessage.Cc.Add(new MailboxAddress("", addressCc));
|
|
foreach (String addressBcc in emailData.AddressesBcc)
|
|
mailMessage.Bcc.Add(new MailboxAddress("", addressBcc));
|
|
foreach (String addressBcc in emailData.Config.Message.AddressesBcc)
|
|
mailMessage.Bcc.Add(new MailboxAddress("", addressBcc));
|
|
|
|
// Body builder.
|
|
var builder = new BodyBuilder();
|
|
|
|
// First add the message itself.
|
|
mailMessage.Subject = emailData.Subject;
|
|
if (emailData.HtmlBody)
|
|
builder.HtmlBody = emailData.MessageBody;
|
|
else
|
|
builder.TextBody = emailData.MessageBody;
|
|
|
|
// Attachments.
|
|
int attachmentCount = 0;
|
|
foreach (SaEmailAttachmentData attachmentData in emailData.Attachments)
|
|
{
|
|
attachmentCount++;
|
|
|
|
// Construct attachment.
|
|
MimePart attachment = new MimePart(attachmentData.ContentType.MediaType, attachmentData.ContentType.MediaSubtype)
|
|
{
|
|
Content = new MimeContent(new MemoryStream(attachmentData.Data)),
|
|
ContentDisposition = new ContentDisposition(attachmentData.Inline ? ContentDisposition.Inline : ContentDisposition.Attachment),
|
|
ContentTransferEncoding = ContentEncoding.Base64
|
|
};
|
|
|
|
// All attachments should have a Filename.
|
|
attachment.FileName = attachmentData.Filename;
|
|
if (StringUtil.IsEmpty(attachment.FileName))
|
|
attachment.FileName = "Attachment_" + StringUtil.PadLeft(attachmentCount.ToString(), 3, '0') + ".dat";
|
|
|
|
// Inline attachments also have a ContentId.
|
|
if (attachmentData.Inline)
|
|
{
|
|
attachment.ContentId = attachmentData.ContentId;
|
|
if (StringUtil.IsEmpty(attachmentData.ContentId))
|
|
attachmentData.ContentId = "Attachment_" + StringUtil.PadLeft(attachmentCount.ToString(), 3, '0') + "@saxonite.com";
|
|
|
|
// Add the inline attachment as a linked resource.
|
|
builder.LinkedResources.Add(attachment);
|
|
}
|
|
else
|
|
{
|
|
// Add the attachment.
|
|
builder.Attachments.Add(attachment);
|
|
}
|
|
}
|
|
|
|
// Populate the message body.
|
|
mailMessage.Body = builder.ToMessageBody();
|
|
|
|
return mailMessage;
|
|
}
|
|
|
|
//-------------------------------------------------------------------
|
|
// Replace dynamic Email Body tags.
|
|
//-------------------------------------------------------------------
|
|
// Tags.
|
|
/// <summary>Check whether the body includes a specific tag.</summary>
|
|
public static bool EmailContainsTag(SaEmailData emailData, String tag)
|
|
{
|
|
return (Regex.Matches(emailData.MessageBody, Regex.Escape(tag), RegexOptions.IgnoreCase).Count > 0);
|
|
}
|
|
/// <summary>Replace a dynamic tag in the email message.</summary>
|
|
public static void ReplaceDynamicEmailTag(SaEmailData emailData, String tag, String content)
|
|
{
|
|
if (EmailContainsTag(emailData, tag))
|
|
emailData.MessageBody = Regex.Replace(emailData.MessageBody, Regex.Escape(tag), content ?? "", RegexOptions.IgnoreCase);
|
|
}
|
|
/// <summary>
|
|
/// Replace dynamic tags in email message that are known to the base project eg.:
|
|
/// <para>- stylesheet (including style tags).</para>
|
|
/// </summary>
|
|
public static void ReplaceDynamicEmailTags(SaEmailData emailData)
|
|
{
|
|
// Nothing to do.
|
|
}
|
|
|
|
//-------------------------------------------------------------------
|
|
protected void AddInlineImageToEmail(SaEmailData emailData, String imageResourceName, byte[] imageData, String imageType = "png")
|
|
{
|
|
string tag = "[#image." + imageResourceName + "]";
|
|
String imageFilename = Regex.Replace(imageResourceName, "_" + imageType, "." + imageType);
|
|
if (Regex.Matches(emailData.MessageBody, Regex.Escape(tag), RegexOptions.IgnoreCase).Count > 0)
|
|
{
|
|
String imageContentId = FormatAttachmentContentId(Regex.Replace(imageFilename, "\\.", "_"));
|
|
if (!emailData.Attachments.Exists(item => StringUtil.EmptyOnNull(item.ContentId).EqualsCI(imageContentId)))
|
|
{
|
|
// Image not yet in attachments.
|
|
SaEmailAttachmentData attachment = new SaEmailAttachmentData("image", imageResourceName)
|
|
{
|
|
Filename = imageFilename,
|
|
ContentId = imageContentId,
|
|
Data = imageData,
|
|
Inline = true
|
|
};
|
|
emailData.Attachments.Add(attachment);
|
|
}
|
|
String content = "cid:" + imageContentId;
|
|
emailData.MessageBody = Regex.Replace(emailData.MessageBody, Regex.Escape(tag), content, RegexOptions.IgnoreCase);
|
|
}
|
|
}
|
|
|
|
//-------------------------------------------------------------------
|
|
public static String FormatAttachmentContentId(String attachmentName)
|
|
{
|
|
// Inline content Ids should be formatted similar to an email address (user@domain).
|
|
// Replace '@' and whitespace with underscores and add domain.
|
|
String contentId = Regex.Replace(Regex.Replace(Regex.Replace(attachmentName, "@", "_"), "\\s+", "_"), "_+", "_") + "@saxonite.com";
|
|
return contentId;
|
|
}
|
|
|
|
//-------------------------------------------------------------------
|
|
}
|
|
//=======================================================================
|
|
}
|