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.
Related
Im trying to send an email with the office 365 smtp, but im getting the following error:
The SMTP server requires a secure connection or the client was not authenticated. The server response was: 5.7.57
Client not authenticated to send mail. Error: 535 5.7.139
Authentication unsuccessful, the user credentials were incorrect.
[XXXX.XXXX.prod.outlook.com]
I noticed that some things got changed "recently" with the office 365 smtp and the most recent code, that I found, that works for most people was this:
SmtpClient mySmtpClient = new SmtpClient();
mySmtpClient.Host = "smtp.office365.com";
mySmtpClient.Port = 587;
mySmtpClient.UseDefaultCredentials = false;
mySmtpClient.DeliveryMethod = SmtpDeliveryMethod.Network;
mySmtpClient.Credentials = new NetworkCredential(email, password);
mySmtpClient.TargetName = "STARTTLS/smtp.office365.com";
mySmtpClient.EnableSsl = true;
// add from,to mailaddresses
MailAddress from = new MailAddress(email);
MailAddress to = new MailAddress(email);
MailMessage myMail = new System.Net.Mail.MailMessage(from, to);
// set subject and encoding
myMail.Subject = "Test message";
myMail.SubjectEncoding = System.Text.Encoding.UTF8;
// set body-message and encoding
myMail.Body = "<b>Test Mail</b><br>using <b>HTML</b>.";
myMail.BodyEncoding = System.Text.Encoding.UTF8;
// text or html
myMail.IsBodyHtml = true;
mySmtpClient.Send(myMail);
But Im still getting the same error as before (MustIssueStartTlsFirst).
Anyone know the problem?
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?
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
I have an .Net 4.5 application that sends an email, with an attachment. It works as expected when the email is opened on a desktop, but when opened on a mobile (iPhone in this case) the attachment shows as inline HTML not as an attachment.
When however I forward the same email from my desktop to the phone, the attachment shows up correctly on my phone so I am almost certain that it has to do with how I am specifying mime or content-type, disposition etc. but I can't see what I am doing wrong.
Here is the code - note that
att.ContentType = new System.Net.Mime.ContentType("multipart/mixed");
does create an attachment on iPhone but it is of type = mime-attachment that will not open.
I'm stumped & client awaits - any help greatly appreciated !
private void SendNotice(string body, string attachment, string email, bool pdf = false)
{
MailMessage message = new MailMessage();
message.From = new MailAddress(ConfigurationManager.AppSettings["SMTP.SendFrom"]);
message.Subject = ConfigurationManager.AppSettings["MatchedNoticeSubject"];
message.To.Add(new MailAddress(email));
message.ReplyToList.Add(new MailAddress(ConfigurationManager.AppSettings["SMTP.ReplyTo"]));
message.Body = body;
message.IsBodyHtml = true;
Attachment att = Attachment.CreateAttachmentFromString(attachment, "SeniorInfo.html", System.Text.Encoding.ASCII, "text/html");
//specifying this creates an attachment of type "mime-attachment" that does not open
//att.ContentType = new System.Net.Mime.ContentType("multipart/mixed");
message.Attachments.Add(att);
SmtpClient server = new SmtpClient()
{
EnableSsl = (ConfigurationManager.AppSettings["SMTP.EnableSSL"].ToLower() == "true"),
Host = ConfigurationManager.AppSettings["SMTP.Server"],
Port = Convert.ToInt16(ConfigurationManager.AppSettings["SMTP.Port"]),
Credentials = new System.Net.NetworkCredential(ConfigurationManager.AppSettings["SMTP.Account"], ConfigurationManager.AppSettings["SMTP.Password"])
};
server.Send(message);
}
Solved after some trial and error fiddling.
Counter-intuitively the attachment ContentDisposition object is READONLY which lead me to believe that I couldn't meddle in it however the read object is apparently a reference to the actual Attachment.ContentDisposition since setting values on the read instance does (apparently) correct the problem. Also used the Enum for MediaTypeNames (System.Net.Mime.MediaTypeNames.Text.Html) tho I don't think that was the issue.
Email send now looks like this :
private void SendMatchNotice(string body, string attachment, string email, bool pdf = false)
{
MailMessage message = new MailMessage();
message.From = new MailAddress(ConfigurationManager.AppSettings["SMTP.SendFrom"]);
message.Subject = ConfigurationManager.AppSettings["MatchedNoticeSubject"];
message.To.Add(new MailAddress(email));
message.ReplyToList.Add(new MailAddress(ConfigurationManager.AppSettings["SMTP.ReplyTo"]));
message.Body = body;
message.IsBodyHtml = true;
// Create the file attachment for this e-mail message.
Attachment att = Attachment.CreateAttachmentFromString(attachment, "SeniorInfo.html", System.Text.Encoding.ASCII, System.Net.Mime.MediaTypeNames.Text.Html);
System.Net.Mime.ContentDisposition disposition = att.ContentDisposition;
disposition.DispositionType = "attachment";
disposition.Inline = false;
disposition.FileName = "SeniorInfo.html";
disposition.CreationDate = DateTime.Now;
disposition.ModificationDate = DateTime.Now;
disposition.ReadDate = DateTime.Now;
message.Attachments.Add(att);
SmtpClient server = new SmtpClient()
{
EnableSsl = (ConfigurationManager.AppSettings["SMTP.EnableSSL"].ToLower() == "true"),
Host = ConfigurationManager.AppSettings["SMTP.Server"],
Port = Convert.ToInt16(ConfigurationManager.AppSettings["SMTP.Port"]),
Credentials = new System.Net.NetworkCredential(ConfigurationManager.AppSettings["SMTP.Account"], ConfigurationManager.AppSettings["SMTP.Password"])
};
server.Send(message);
}
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.