Send encrypted and signed email using C# - c#

I want to send an encrypted and signed mail without using any third-party API.
If I send only the alternate view with the signature, Windows Mail can validate it. If I send only with alternate view with encrypted data, Windows Mail can decipher it. But if I send both, Windows Mail gets 2 attachements. If I sign the encryptedBytes and add those signed bytes to the alternative view it only validates the signature and the message is empty.
Any idea?
MailMessage message = new MailMessage();
message.From = new MailAddress(lblMail.Text);
message.Subject = txtSubject.Text;
string body = "Content-Type: text/plain\r\nContent-Transfer-Encoding: 7Bit\r\n\r\n" + structForm();
byte[] messageData = Encoding.ASCII.GetBytes(body);
ContentInfo content = new ContentInfo(messageData);
EnvelopedCms envelopedCms = new EnvelopedCms(content);
message.To.Add(new MailAddress(provMail));
CmsRecipient recipient = new CmsRecipient(SubjectIdentifierType.SubjectKeyIdentifier, this.certificate);
envelopedCms.Encrypt(recipient);
byte[] encryptedBytes = envelopedCms.Encode();
SignedCms Cms = new SignedCms(new ContentInfo(encryptedBytes));
CmsSigner Signer = new CmsSigner(SubjectIdentifierType.IssuerAndSerialNumber, new X509Certificate2(#"c:\serv.pfx","123"));
Cms.ComputeSignature(Signer);
byte[] SignedBytes = Cms.Encode();
MemoryStream encryptedStream = new MemoryStream(encryptedBytes);
AlternateView encryptedView = new AlternateView(encryptedStream, "application/pkcs7-mime; smime-type=signed--data;name=smime.p7m");
message.AlternateViews.Add(encryptedView);
MemoryStream signedStream = new MemoryStream(SignedBytes);
AlternateView signedView = new AlternateView(signedStream, "application/pkcs7-mime; smime-type=signed-data;name=sig.p7m");
message.AlternateViews.Add(signedView);
System.Net.NetworkCredential SMTPUserInfo = new System.Net.NetworkCredential("emailaddress#xpto.com", "XXXXXX");
SmtpClient client = new SmtpClient("smtp.xpto.com");
client.UseDefaultCredentials = false;
client.Credentials = SMTPUserInfo;
client.Send(message);
Label2.Text = "Assinado e cifrado!";

You should sign first, then encrypt.
While the original CMS and S/MIME specifications allow you to do the operations in either order, later work pointed out that signing a document that you can't read is a really bad idea. The signature should be over the plain-text.
The resulting MIME message should only have a single part, which should be S/MIME enveloped-data. Your message has two parts, and the encrypted part is mis-labeled with a signed-data content-type. Create and sign the SignedCms object. Encode it, and use the encoded value as the content of an EnvelopedCms object. Encrypt that, and use its encoded value as the content of your MailMessage, with a content type of "application/pkcs7-mime; smime-type=enveloped-data".

Related

S/Mime with attachment sign using MailSystem.Net

I'm new to s/mime and need to digitally sign email with xml attachment, but unfortunately this email has a wrong hash value (according to response of external system). I digged into the code of the library and found that it creates a sign for base64-encoded body part, is it correct or the signature should be computed for xml attachment content?
Also here is some more issues:
Lots of headers/parameters are owerritten by library: for ex. ContentType parameters, some headers (like X-Mailer) and many others
It creates an empty boundary for Content-Type: text/plain, though I haven't any text except attachment
Here is my code:
public static void Sign(X509Certificate2 clientCert, string from, string to, string subject, string attachementPath)
{
Message message = new Message();
message.From = new Address(from);
message.To.Add(to);
message.ContentType.MimeType = "multipart/signed";
message.ContentType.Parameters.Add("protocol", "\"application/pkcs7-signature\"");
message.ContentTransferEncoding = ContentTransferEncoding.SevenBits;
message.AddHeaderField("MIME-Version", "1.0");
message.Subject = subject;
var mimePart = new MimePart(attachementPath, false);
mimePart.ContentTransferEncoding = ContentTransferEncoding.Base64;
mimePart.Charset = "windows-1251";
mimePart.ContentType.MimeType = "text/xml";
message.Attachments.Add(mimePart);
message.BuildMimePartTree();
CmsSigner signer = new CmsSigner(clientCert);
signer.IncludeOption = X509IncludeOption.EndCertOnly;
message.SmimeAttachSignatureBy(signer);
}

Convert byte[] to PDF Sharp Document and Email as Attachment

I am using the PDF Sharp library to create a custom PDF. I want to be able to email this custom PDF as an attachment without saving a local copy first. The way I am trying to achieve this is by converting the generated PDF Sharp document to a byte array as follows:
byte[] pdfBuffer = null;
using (MemoryStream ms = new MemoryStream())
{
document.Save(ms, false);
pdfBuffer = ms.ToArray();
}
This part seems to be working, however the part I am hving problems with is converting the byte array back a PDF file. With the code below the PDF is being attached to the email but when the attachment is opened it is a blank file. This is the code I am using to do that:
//Add PDF attachment.
Stream stream = new MemoryStream(attachmentData);
mailMessage.Attachments.Add(new Attachment(stream, attachmentFilename, "application/pdf"));
//Setup up SMTP details.
smtpClient = new SmtpClient("************.com");
smtpUserInfo = new System.Net.NetworkCredential("****#****.com", "*****", "*****.com");
smtpClient.Credentials = smtpUserInfo;
smtpClient.UseDefaultCredentials = false;
smtpClient.DeliveryMethod = SmtpDeliveryMethod.Network;
//Send the email.
smtpClient.Send(mailMessage);
Can anyone please explain a correct way of converting the PDF stream back to a valid PDF and send is an email attachment?
The reason the document was appearing blank when I converted the stream back to a PDF is that when using document.Save(memoryStream, false);, it is neccessary to call document.Close(); after, i.e.:
document.Save(memoryStream, false);
document.Close();
WebClient User = new WebClient();
Byte[] FileBuffer = User.DownloadData(strPDFPath);
Stream stream = new MemoryStream(FileBuffer);
ContentType ct = new ContentType(MediaTypeNames.Application.Pdf);
pdf = new Attachment(stream, ct);
pdf.ContentType.MediaType = MediaTypeNames.Application.Pdf;
msg.Attachments.Add(pdf);
pdf.ContentType.Name = Path.GetFileName(strPDFPath);

Get file to send as attachment from byte array

I have an ASP.NET MVC application that has to send an email to a list of recipients with an attachment detailing a specific "Project". I get the details for this from a report by making use of SQL Server Reporting Services (SSRS).
I've never really used SSRS before, but I received some code from a colleague where he used it. What he does with the report is he downloads it in the browser to the client's machine. So, if I don't do that I sit with a byte array containing the report data.
Is there a way I can send this as an attachment without first physically writing the file to the filesystem of the server? The report will either be in excel format or a pdf.
Edit: I am using SmtpClient to send the email's.
Get the file data in a byte[]
byte[] binaryFile = // get your file data from the SSRS ...
string filename = "SSRS.pdf";
Prepare a list or array of the destination addresses:
string[] addresses = // get addresses somehow (db/hardcoded/config/...)
sending smtp message through SmtpClient:
MailMessage mailMessage= new MailMessage();
mailMessage.From = new MailAddress("sender email address goes here");
// Loop all your clients addresses
foreach (string address in addresses)
{
mailMessage.To.Add(address);
}
mailMessage.Subject = "your message subject goes here";
mailMessage.Body = "your message body goes here";
MemoryStream memoryStream = new MemoryStream(binaryFile);
mailMessage.Attachments.Add( new Attachment( memoryStream, filename , MediaTypeNames.Application.Pdf ));
SmtpClient smtpClient = new SmtpClient();
smtpClient.Send(mailMessage);
to do this you would need to leverage off the SSRS ReportManager API as follows.
First read in the report from the Web Service with SSRS
Read the file into memory rather than saving to the server or client
Send the MemoryStream object straight to the email server.
Reporting services: Get the PDF of a generated report
How to send an email with attachments using SmtpClient.SendAsync?
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);
}
}

Best way for sending advance email

I'd like to send email by asp.net . I use this code and it is work fine.
mail.From = new MailAddress("mail#gmail.com", "sender", System.Text.Encoding.UTF8);
string to = Session["Umail"].ToString();
mail.To.Add(to);
mail.IsBodyHtml = true;
mail.SubjectEncoding = Encoding.UTF8;
mail.BodyEncoding = Encoding.GetEncoding("utf-8");
mail.Subject = "subject";
mail.Body = "body" ;
SmtpClient smtp = new SmtpClient("Smtp.gmail.Com", 587);
smtp.UseDefaultCredentials = false;
smtp.EnableSsl = true;
smtp.Credentials = new NetworkCredential("mail#gmail.com", "pass"); smtp.Send(mail);
But I'd like a custom and beautiful mail. Like emails that send from facebook, google team and etc. I know that can use html tag in mail.Body but is it good way? What is the best way ?
This is ready to use code snippet which I use for sending email which contains both text content and the content based on a html template:
// first we create a plain text version and set it to the AlternateView
// then we create the HTML version
MailMessage msg = new MailMessage();
msg.From = new MailAddress("from#email", "From Name");
msg.Subject = "Subject";
msg.To.Add("to#email");
msg.BodyEncoding = Encoding.UTF8;
String plainBody = "Body of plain email";
//first we create the text version
AlternateView plainView = AlternateView.CreateAlternateViewFromString(plainBody, Encoding.UTF8, "text/plain");
msg.AlternateViews.Add(plainView);
//now create the HTML version
MailDefinition message = new MailDefinition();
message.BodyFileName = "~/MailTemplates/template1.htm";
message.IsBodyHtml = true;
message.From = "from#email";
message.Subject = "Subject";
//Build replacement collection to replace fields in template1.htm file
ListDictionary replacements = new ListDictionary();
replacements.Add("<%USERNAME%>", "ToUsername");//example of dynamic content for Username
//now create mail message using the mail definition object
//the CreateMailMessage object takes a source control object as the last parameter,
//if the object you are working with is webcontrol then you can just pass "this",
//otherwise create a dummy control as below.
MailMessage msgHtml = message.CreateMailMessage("to#email", replacements, new LiteralControl());
AlternateView htmlView = AlternateView.CreateAlternateViewFromString(msgHtml.Body, Encoding.UTF8, "text/html");
//example of a linked image
LinkedResource imgRes = new LinkedResource(Server.MapPath("~/MailTemplates/images/imgA.jpg"), System.Net.Mime.MediaTypeNames.Image.Jpeg);
imgRes.ContentId = "imgA";
imgRes.ContentType.Name = "imgA.jpg";
imgRes.TransferEncoding = System.Net.Mime.TransferEncoding.Base64;
htmlView.LinkedResources.Add(imgRes);
msg.AlternateViews.Add(htmlView);
//sending prepared email
SmtpClient smtp = new SmtpClient();//It reads the SMPT params from Web.config
smtp.Send(msg);
and these are key parts of the html template:
<p>Username: <%USERNAME%></p>
<img src="cid:imgA"/>
I'd like a custom and beautiful mail.
I know that can use html tag in mail.Body but is it good way? What is
the best way ?
I don't know exactly what is that supposed to mean, but generally, there are two ways to do it. (If we talking about images or sources in email etc..)
You can use LinkedResource class of .NET Framework.
Represents an embedded external resource in an email attachment, such
as an image in an HTML attachment.
Alternatively, and more simply in my opinion, if you want to use some images in your email, put the image in a public location then just reference that location in the HTML of the email.

Send url with querystring with SmtpClient

Basic question here: I'm sending emails using the default SmtpClient of the .NET framework (3.5). The bodytype is HTML (IsBodyHtml = true) In the body I've added a url with two parameters in the querystring like so:
http://server.com/page.aspx?var1=foo&var2=bar
This get's encoded to:
http://server.com/page.aspx?var1=foo%26var2=bar (the ampersand is encoded as percent-26)
When doing a simple Request["var2"] I get 'null'.
What should I do to properly encode the ampersand in the mail message?
This works fine for me:
var client = new SmtpClient();
client.Host = "smtp.somehost.com";
var message = new MailMessage();
message.From = new MailAddress("from#example.com");
message.To.Add(new MailAddress("to#example.com"));
message.IsBodyHtml = true;
message.Subject = "test";
string url = HttpUtility.HtmlEncode("http://server.com/page.aspx?var1=foo&var2=bar");
message.Body = "<html><body>Test</body></html>";
client.Send(message);
Use the UrlEncode method. This will do all the encoding of your input string for you.

Categories

Resources