0

I'm trying to send an email with a certificate PFX, I can read the certificate with a password and add it to the mail client.

I'm also using an Alternate View to insert the image to the message Base64

The problem is the email is not signed, and I'm missing something.

I researched a lot but the outcome was not expected.

public static void SendEmailSmtpRelay(string subject, string text, MailAddress from, MailAddress to, List<MailAddress> cc, List<MailAddress> bcc = null, string pass = null)

private static Stream Base64ToImageStream(string base64String)

private static AlternateView ContentToAlternateView(string content, out string contentReplaced)
public static void SendEmailSmtpRelay(string subject, string text, MailAddress from, MailAddress to, List<MailAddress> cc, List<MailAddress> bcc = null, string pass = null)
{
    String mailPassword = @"xc8ByK0GRODq4 /GQfXjdbmAP2x5+3PZidnsgXu2RdeBEMJGV8uGS3uXP92WJsG6OVc/2K/vX0m2IGQ8lmZP0wl40TtmdsNwZxjD6Ah/FwiU1QAmD03LylGXrJfdC7Kmb";
    var fileName = AssemblyDirectory + @"\" + "cert.pfx";
    var cipher = StringCipher.Decrypt(mailPassword, pass);
    SecureString secureMailpassword = new SecureString();

    foreach (char c in cipher)
    {
        secureMailpassword.AppendChar(c);
    }
    
    var mailClient = new SmtpClient();
    mailClient.Host = "mail.mycorp.com";
    mailClient.Port = 25;
    mailClient.EnableSsl = true;
    mailClient.DeliveryMethod = SmtpDeliveryMethod.Network;
    mailClient.UseDefaultCredentials = false;
    mailClient.Credentials = new NetworkCredential("USER", cipher);
    var msgMail = new MailMessage
    {
        From = from
    };
    msgMail.To.Add(to);
    foreach (var addr in cc)
    {
        msgMail.CC.Add(addr);
    }
    if (bcc != null)
    {
        foreach (var addr in bcc)
        {
            msgMail.Bcc.Add(addr);
        }
    }
    
    X509Certificate2 cert = new X509Certificate2(fileName, "pass");
    byte[] data = Encoding.ASCII.GetBytes(text);
    ContentInfo content = new ContentInfo(data);
    SignedCms signedCms = new SignedCms(content, false);
    CmsSigner signer = new CmsSigner(SubjectIdentifierType.IssuerAndSerialNumber, cert);
    signedCms.ComputeSignature(signer);
    byte[] signedbytes = signedCms.Encode();

    msgMail.Subject = subject;
    msgMail.Body = text;
    msgMail.IsBodyHtml = true;
    //msgMail.AlternateViews.Add(av);
    string _replaced = String.Empty;
    AlternateView alterView = ContentToAlternateView(text, out _replaced);
    msgMail.Body = _replaced;
    msgMail.AlternateViews.Add(alterView);
    mailClient.Send(msgMail);
    msgMail.Dispose();
}

/* *
https://stackoverflow.com/questions/39407474/add-attachment-base64-image-in-mailmessage-and-read-it-in-html-body
* */

private static Stream Base64ToImageStream(string base64String)
{
    byte[] imageBytes = Convert.FromBase64String(base64String);
    MemoryStream ms = new MemoryStream(imageBytes, 0, imageBytes.Length);
    return ms;
}

private static AlternateView ContentToAlternateView(string content, out string contentReplaced)
{
    int imgCount = 0;
    List<LinkedResource> resourceCollection = new List<LinkedResource>();

    Regex regex = new Regex(@"<img[^>]+src=['""]([^ "">]+)['""]");
    MatchCollection matchCollection = regex.Matches(content);
    //

    foreach (Match m in matchCollection)
    {
        imgCount++;
        string imgContent = m.Groups[1].Value;
        string type = Regex.Match(imgContent, "data:(?<type>.*?);base64,").Groups["type"].Value;

        Regex b64contentRegex = new Regex(@"base64,(.*)");
        MatchCollection base64ContentMatchCollection = b64contentRegex.Matches(imgContent);
        string base64Content = String.Empty;
        if (base64ContentMatchCollection.Count > 0 && base64ContentMatchCollection[0].Groups.Count > 1)
        {
            base64Content = base64ContentMatchCollection[0].Groups[1].Value;
        }

        if (String.IsNullOrEmpty(type) || String.IsNullOrEmpty(base64Content))
        {
            //ignore replacement when match normal <img> tag
            continue;
        }
        string replacement = "cid:" + imgCount;
        content = content.Replace(imgContent, replacement);
        LinkedResource tempResource = new LinkedResource(Base64ToImageStream(base64Content), new ContentType(type))
        {
            ContentId = imgCount.ToString(),
        };
        resourceCollection.Add(tempResource);
        

    }

    AlternateView alternateView = AlternateView.CreateAlternateViewFromString(content, null, MediaTypeNames.Text.Html);
    foreach (var item in resourceCollection)
    {
        alternateView.LinkedResources.Add(item);
    }

    contentReplaced = content;
    return alternateView;
}
James Z
  • 12,209
  • 10
  • 24
  • 44
Joao Livio
  • 89
  • 1
  • 1
  • 13
  • The output from ContentToAlternateView should look like a MIME attachment. See mime example : https://learn.microsoft.com/en-us/previous-versions/office/developer/exchange-server-2010/aa563375(v=exchg.140)?force_isolation=true – jdweng Jan 26 '22 at 14:47
  • hi @jdweng, I'm trying in the ContentAlterateView() with ```string mimeType = System.Web.MimeMapping.GetMimeMapping(fileName); System.Net.Mail.Attachment attach = new System.Net.Mail.Attachment(fileName, new System.Net.Mime.ContentType(mimeType)); resourceCollection.Add(new LinkedResource(attach.ContentStream));``` no luck – Joao Livio Jan 26 '22 at 16:36

1 Answers1

0

doing this works

X509Certificate2 cert = new X509Certificate2(fileName, "pass");

byte[] data = Encoding.ASCII.GetBytes(text);
ContentInfo content = new ContentInfo(data);
SignedCms signedCms = new SignedCms(content, false);
CmsSigner signer = new CmsSigner(SubjectIdentifierType.IssuerAndSerialNumber, cert);
signedCms.ComputeSignature(signer);
byte[] signedbytes = signedCms.Encode();
mailClient.ClientCertificates.Add(cert);

MemoryStream ms = new MemoryStream(signedbytes);
AlternateView av = new AlternateView(ms, "application/pkcs7-mime; smime-type=signed-data;name=smime.p7m");

You can also use this framework https://www.codeproject.com/Articles/41727/An-S-MIME-Library-for-Sending-Signed-and-Encrypted

Joao Livio
  • 89
  • 1
  • 1
  • 13