How send signed email with attachment - c#

I have method, which sign my email by certificate. This work fine if the line with adding an attachment is commented out.
private static void mailer()
{
MailAddress from = new MailAddress("test#email.cz");
MailAddress to = new MailAddress("test#email.cz");
MailMessage message = new MailMessage(from, to);
message.Subject = "Test subject email";
message.IsBodyHtml = true;
string body = "Content-Type: text/html; charset=utf-8 \r\n Content-Transfer-Encoding: 7bit \r\n\r\n";
body += " Email body signed by certificate ";
byte[] messageData = Encoding.ASCII.GetBytes(body);
SignedCms Cms = new SignedCms(new ContentInfo(messageData));
RSACryptoServiceProvider csp = null;
X509Certificate2 cert = new X509Certificate2(#"C:\TFS\cert_test.p12", "password");
if (cert != null)
{
csp = (RSACryptoServiceProvider)cert.PrivateKey;
}
else
{
throw new Exception("Valid certificate was not found");
}
CmsSigner Signer = new CmsSigner(SubjectIdentifierType.IssuerAndSerialNumber, cert);
Cms.ComputeSignature(Signer);
byte[] SignedBytes = Cms.Encode();
MemoryStream signedStream = new MemoryStream(SignedBytes);
AlternateView signedView = new AlternateView(signedStream, "application/pkcs7-mime; smime-type=signed-data; name=sig.p7m");
message.AlternateViews.Add(signedView);
ContentType contentType = new ContentType();
contentType.MediaType = MediaTypeNames.Application.Octet;
contentType.Name = "test.xml";
MemoryStream ms = new MemoryStream(fileData);
ms.Position = 0;
Attachment attachment = new Attachment(ms, contentType);
//message.Attachments.Add(attachment);
SmtpClient client = new SmtpClient("smtp.server.net");
client.UseDefaultCredentials = false;
client.Credentials = new System.Net.NetworkCredential("smtp.server.net", "password", "user");
try
{
client.Send(message);
}
catch (Exception ex)
{
throw ex;
}
}
But I must add attachments (3 or more) to email. When I add an attachment (just one attachment yet), the email no longer shows as signed and the body of email doesn't show up. I find some samples of my problem, but it useless for me.
I don't encrypt the body of email and an attachment. I need only sign an email by certificate.
Thanks for help.
EDIT: Sorry, I had commented out the line with adding signed AlternateView. Right commented out the line is with adding attachment to the email.

Related

s/mime signed message cannot be open by outlook

I need to digitally sign email using s/mime. I've created a detached signature for my attachment but outlook can't open it: "Cannot open this item. Your Digital ID name cannot be found by the underlying security system". Certificate is installed on this PC and there is smth need to be tweaked in this code:
const int CHARS_IN_LINE = 64;
StringBuilder message = new StringBuilder();
message.AppendLine("Content-Type: multipart/signed; protocol=\"application/pkcs7-signature\";");
message.AppendLine(" boundary=\"__multipart-signed-boundary__\"");
message.AppendLine("Content-Transfer-Encoding: 7bit");
message.AppendLine("MIME-Version: 1.0");
message.AppendLine("Subject: " + tbMessageSubject.Text);
message.AppendLine();
message.AppendLine("--__multipart-signed-boundary__");
message.AppendLine("Content-Type: text/xml; charset=\"windows - 1251\"");
message.AppendLine("Content-Disposition: attachment; ");
message.AppendLine(" filename=\"" + Path.GetFileName(filename) + "\"");
message.AppendLine("Content-Transfer-Encoding: base64");
message.AppendLine();
var dataToSign = File.ReadAllBytes(filePath);
var base64Data = Convert.ToBase64String(dataToSign, Base64FormattingOptions.None);
var base64DataSb = new StringBuilder(base64Data);
for (int i = CHARS_IN_LINE; i < base64DataSb.Length; i += CHARS_IN_LINE + 2) // \r\n
base64DataSb.Insert(i, "\r\n");
message.AppendLine(base64DataSb.ToString());
message.AppendLine("--__multipart-signed-boundary__");
message.AppendLine("Content-Type: application/pkcs7-signature; name=\"smime.p7m\"");
message.AppendLine("Content-Transfer-Encoding: base64");
message.AppendLine("Content-Disposition: attachment; filename=smime.p7s");
message.AppendLine();
CmsSigner signer = new CmsSigner(clientCert);
SignedCms cms = new SignedCms(new ContentInfo(dataToSign), true);
cms.ComputeSignature(signer);
var signature = cms.Encode();
var base64Signature = Convert.ToBase64String(signature, Base64FormattingOptions.None);
var base64Sb = new StringBuilder(base64Signature);
for (int i = CHARS_IN_LINE; i < base64Sb.Length; i += CHARS_IN_LINE + 2) // \r\n
base64Sb.Insert(i, "\r\n");
message.AppendLine(base64Sb.ToString());
message.AppendLine();
message.AppendLine("--__multipart-signed-boundary__--");
message.AppendLine(".");
var stream = new MemoryStream(Encoding.ASCII.GetBytes(message.ToString()));
MailMessage mail = new MailMessage();
mail.From = new MailAddress(tbEmailFrom.Text);
mail.To.Add(new MailAddress(tbEmailTo.Text));
AlternateView alternateView = new AlternateView(stream, "application/pkcs7-mime; smime-type=signed-data; name=smime.p7m");
alternateView.TransferEncoding = TransferEncoding.SevenBit;
mail.AlternateViews.Add(alternateView);
SmtpClient client = new SmtpClient(host, port);
client.EnableSsl = chbUseSSL.Checked;
client.Send(mail);
Finally, the issue was in specified mediaType in AlternateView, the correct way:
AlternateView alternateView = new AlternateView(stream, "multipart/signed; protocol=\"application/pkcs7-signature\"; boundary=\"__multipart-signed-boundary__\"");
alternateView.TransferEncoding = TransferEncoding.SevenBit;
and thanks to jdweng, I was need to sign not the attachment, but the attachment with it's headers (first __multipart-signed-boundary with attachment)

Send encrypted AND signed mail with .NET MailMessage in c#

I want to send an encrypted and signed mail without using any third-party library.
I'm able to send an email signed or encrypted. But both is not working.
I've tried to send a mail with Thunderbird and looked at the source, but theres nothing that tells the mail is encrypted and signed.
When I use following code
byte[] bodyBytes = Encoding.UTF8.GetBytes("TestBody");
SignedCms cms = new SignedCms(new ContentInfo(bodyBytes), false);
CmsSigner signer = new CmsSigner(SubjectIdentifierType.IssuerAndSerialNumber, signerCert); //X509Certificate2 with private key of sender
cms.ComputeSignature(signer);
byte[] signedBytes = cms.Encode();
EnvelopedCms ecms = new EnvelopedCms(new ContentInfo(signedBytes));
CmsRecipient cmsr = new CmsRecipient(SubjectIdentifierType.IssuerAndSerialNumber, encryptCert); //X509Certificate2 with public key of recipient
ecms.Encrypt(cmsr);
byte[] encryptedBytes = ecms.Encode();
MailMessage msg = new MailMessage();
msg.To.Add(new MailAddress(to));
msg.From = new MailAddress(from);
msg.Subject = subject;
MemoryStream ms = new MemoryStream(encryptedBytes);
AlternateView av = new AlternateView(ms, "application/pkcs7-mime; smime-type=enveloped-data;name=smime.p7m");
msg.AlternateViews.Add(av);
SmtpClient smtp = new SmtpClient("[smtpServer]", 25);
smtp.Send(msg);
the MailClient just decrypts or checks the signature of the message.. the action which i perform last. How can I tell the Client to do both, decryption and signature check?

Encrypte and Signed email using C#

I how can I have email encrypted and signed ?
Seem that I can either encrypt or signed but not both.
Below is my code
public void SendEncryptedEmail04(
//string SigningCertPath, string EncryptingCertPath,
String sender, String To,
string Subject, string Body,
// string SmtpServer, int SmtpPort, bool HTML)
bool HTML)
{
X509Certificate2 SignCert = new X509Certificate2("D:\\certwithprivatekey.pfx", "password"));
X509Certificate2 EncryptCert = new X509Certificate2("abc#gmail.crt", "");
StringBuilder Message = new StringBuilder();
Message.AppendLine("Content-Type: text/" + ((HTML) ? "html" : "plain") +
"; charset=\"iso-8859-1\"");
Message.AppendLine("Content-Transfer-Encoding: 7bit");
Message.AppendLine();
Message.AppendLine(Body);
byte[] BodyBytes = Encoding.ASCII.GetBytes(Message.ToString());
EnvelopedCms ECms = new EnvelopedCms(new ContentInfo(BodyBytes));
CmsRecipient Recipient = new CmsRecipient(
SubjectIdentifierType.IssuerAndSerialNumber, EncryptCert);
ECms.Encrypt(Recipient);
byte[] EncryptedBytes = ECms.Encode();
SignedCms Cms = new SignedCms(new ContentInfo(EncryptedBytes));
CmsSigner Signer = new CmsSigner
(SubjectIdentifierType.IssuerAndSerialNumber, SignCert);
Cms.ComputeSignature(Signer);
byte[] SignedBytes = Cms.Encode();
MailMessage Msg = new MailMessage();
Msg.To.Add(new MailAddress(To));
Msg.From = new MailAddress(sender);
Msg.Subject = Subject;
//MemoryStream ms = new MemoryStream(EncryptedBytes);
MemoryStream ms = new MemoryStream(SignedBytes);
AlternateView av = new AlternateView(ms,
"application/pkcs7-mime; smime-type=signed-data;name=smime.p7m");
//"application/pkcs7-mime; smime-type=enveloped-data;name=smime.p7m");
Msg.AlternateViews.Add(av);
SmtpClient smtp = new SmtpClient(emailServer, 25);
smtp.UseDefaultCredentials = false;
smtp.Credentials = new System.Net.NetworkCredential(sender,"xxxx"));
smtp.Send(Msg);
}
The email received by ThunderBird has the following
However, I changed to
MemoryStream ms = new MemoryStream(EncryptedBytes);
I have
How can I have encrypted and signed ?
Thanks

Attach file from internet to mail without saving it in disk in asp.net

I've written a mail sending code for asp.net. it is working fine. I can attach files that are saved on disk. Now I want to attach a file that is on the internet. I can download the file and save it somewhere on disk and attach the file. but I don't want to save the file on disk. I just need to download the file in memory and attach it to my mail. need help to do that.
here is my code for sending email
public void SendMail(string To, string Subject, string Body)
{
MailMessage mail = new MailMessage();
mail.From = new MailAddress("noreply#xyz.com", "xyz");
mail.To.Add(new MailAddress(To));
mail.Subject = Subject;
mail.Body = Body;
mail.IsBodyHtml = true;
using (SmtpClient smtpClient = new SmtpClient())
{
try
{
smtpClient.Send(mail);
}
catch (Exception ex)
{
throw ex;
}
}
}
I want some thing like this
public void SendMail(string To, string Subject, string Body, URI onlineFileURI)
{
MailMessage mail = new MailMessage();
mail.From = new MailAddress("noreply#xyz.com", "xyz");
mail.To.Add(new MailAddress(To));
mail.Subject = Subject;
mail.Body = Body;
mail.IsBodyHtml = true;
//Create the attachment from URL
var attach = [Attachemnt from URL]
mail.Attachments.Add(attach)
using (SmtpClient smtpClient = new SmtpClient())
{
try
{
smtpClient.Send(mail);
}
catch (Exception ex)
{
throw ex;
}
}
}
How I can download the file in memory and attach it?
This is how I ended up doing it based of previous posts:
var url = "myurl.com/filename.jpg"
HttpWebRequest req = (HttpWebRequest)WebRequest.Create(url);
using (HttpWebResponse HttpWResp = (HttpWebResponse)req.GetResponse())
using (Stream responseStream = HttpWResp.GetResponseStream())
using (MemoryStream ms = new MemoryStream())
{
responseStream.CopyTo(ms);
ms.Seek(0, SeekOrigin.Begin);
Attachment attachment = new Attachment(ms, filename, MediaTypeNames.Image.Jpeg);
message.Attachments.Add(attachment);
_smtpClient.Send(message);
}
You can do it by converting page into Stream/byte array and send it
Here is the code
string strReportUser = "RSUserName";
string strReportUserPW = "MySecretPassword";
string strReportUserDomain = "DomainName";
string sTargetURL = "http://SqlServer/ReportServer?" +
"/MyReportFolder/Report1&rs:Command=Render&rs:format=PDF&ReportParam=" +
ParamValue;
HttpWebRequest req =
(HttpWebRequest)WebRequest.Create( sTargetURL );
req.PreAuthenticate = true;
req.Credentials = new System.Net.NetworkCredential(
strReportUser,
strReportUserPW,
strReportUserDomain );
HttpWebResponse HttpWResp = (HttpWebResponse)req.GetResponse();
Stream fStream = HttpWResp.GetResponseStream();
HttpWResp.Close();
//Now turn around and send this as the response..
ReadFullyAndSend( fStream );
ReadFullyAnd send method. NB: the SendAsync call so your not waiting for the server to send the email completely before you are brining the user back out of the land of nod.
public static void ReadFullyAndSend( Stream input )
{
using ( MemoryStream ms = new MemoryStream() )
{
input.CopyTo( ms );
MailMessage message = new MailMessage("from#foo.com", "too#foo.com");
Attachment attachment = new Attachment(ms, "my attachment",, "application/vnd.ms-excel");
message.Attachments.Add(attachment);
message.Body = "This is an async test.";
SmtpClient smtp = new SmtpClient("localhost");
smtp.Credentials = new NetworkCredential("foo", "bar");
smtp.SendAsync(message, null);
}
}
courtesy:Get file to send as attachment from byte array

Making Outlook Recognize My Digitally Signed Email

I am using C# .NET 4.0 to send a signed SMTP mail message like so:
private void SendMailMessage(object data)
{
MailMessage message = new MailMessage();
message.From = new MailAddress(fromAddress);
message.To.Add(new MailAddress(emailTo));
message.Subject = "Subject";
message.IsBodyHtml = true;
message.Body += "Blah blah blah.";
byte[] messageBytes = Encoding.ASCII.GetBytes(message.Body);
SignedCms Cms = new SignedCms(new ContentInfo(messageBytes));
CmsSigner Signer = new CmsSigner(SubjectIdentifierType.IssuerAndSerialNumber, certificate);
Cms.ComputeSignature(Signer);
byte[] SignedBytes = Cms.Encode();
MemoryStream signedStream = new MemoryStream(SignedBytes);
AlternateView signedView = new AlternateView(signedStream, "application/pkcs7-mime; smime-type=signed-data;name=sig.p7m");
message.AlternateViews.Add(signedView);
SmtpClient client = new SmtpClient(smtpServer, int.Parse(smtpServerPort));
client.DeliveryMethod = SmtpDeliveryMethod.Network;
client.Send(message);
message.Dispose();
client = null;
}
From what I can tell, this "works" in that if view the raw data of the message, I see the alternate view with a big PKCS signature in it. But Outlook doesn't recognize it. The Outlook client normally recognizes signed messages and attempts to validate them and puts a little certificate on the message and all that...
I want that... what am I missing?
Edit: I have made some progress on this on my own, but still having some trouble. Here is what the code looks like now:
private void SendMailMessage(string emailTo)
{
MailMessage message = new MailMessage();
message.From = new MailAddress(fromAddress);
message.To.Add(new MailAddress(emailTo));
message.Subject = "Special Delivery";
message.IsBodyHtml = false;
string body = "Content-Type: text/plain;charset=\"iso-8859-1\"\nContent-Transfer-Encoding: quoted-printable\n\nHere is some body text!";
byte[] messageBytes = Encoding.ASCII.GetBytes(body);
ContentInfo content = new ContentInfo(messageBytes);
SignedCms signedCms = new SignedCms(content, false);
CmsSigner Signer = new CmsSigner(SubjectIdentifierType.IssuerAndSerialNumber, certificate);
signedCms.ComputeSignature(Signer);
byte[] signedBytes = signedCms.Encode();
MemoryStream ms = new MemoryStream(signedBytes);
AlternateView av = new AlternateView(ms, "application/pkcs7-mime; smime-type=signed-data;name=smime.p7m");
message.AlternateViews.Add(av);
SmtpClient client = new SmtpClient(smtpServer, int.Parse(smtpServerPort));
client.DeliveryMethod = SmtpDeliveryMethod.Network;
client.Send(message);
message.Dispose();
client = null;
}
Of note is that I left message.Body blank this time, only sending the AlternateView. Now, when I send this to an Outlook inbox, I get the padlock icon over my email, the S/MIME doodad kicks in and tries to verify the signer, but fails. The certificate used to sign the email is issued by a publically trusted CA. Edit: That's my fault, the certificate didn't have the "secure email" usage attribute. I'll get a new certificate.
When I send the same email to a Gmail address, I get a blank message with a *.p7m attachment on it that contains a bunch of garbage.
The code that gets this working in Outlook looks like this:
private void SendMailMessage(string emailTo)
{
MailMessage message = new MailMessage();
message.From = new MailAddress(fromAddress);
message.To.Add(new MailAddress(emailTo));
message.Subject = "Regarding your lottery winnings";
message.IsBodyHtml = false;
string body = "Content-Type: text/plain;charset=\"iso-8859-1\"\nContent-Transfer-Encoding: quoted-printable\n\nBlah blah blah blah blah blah.";
byte[] messageBytes = Encoding.ASCII.GetBytes(body);
ContentInfo content = new ContentInfo(messageBytes);
SignedCms signedCms = new SignedCms(content, false);
CmsSigner Signer = new CmsSigner(SubjectIdentifierType.IssuerAndSerialNumber, emailCert);
signedCms.ComputeSignature(Signer);
byte[] signedBytes = signedCms.Encode();
MemoryStream ms = new MemoryStream(signedBytes);
AlternateView av = new AlternateView(ms, "application/pkcs7-mime; smime-type=signed-data;name=smime.p7m");
message.AlternateViews.Add(av);
SmtpClient client = new SmtpClient(smtpServer, int.Parse(smtpServerPort));
client.DeliveryMethod = SmtpDeliveryMethod.Network;
client.Send(message);
message.Dispose();
client = null;
}
Using a valid certificate, of course. Now when I send this email and view it in Outlook, I get the certificate icon on the email, and the S/MIME control successfully validates the signature, and the text shows up just like I want it to without displaying the headers to the user.
Notice that I have to leave message.Body empty. Putting anything in message.Body will break it.

Categories

Resources