Attachment without filename - c#

When using the System.Net.Mail namespace to send a e-mail with attachment to any Yahoo account the attachment is downloaded with 'untitled' name instead the file name.
In the Yahoo Mail interface the attachment looks with the correct name but when you download it the download name goes to 'untitled' for all attachments. The same e-mail message works fine with Gmail, Outlook.com, Windows Live Mail and other clients.
Looking the raw message it constains a content-type with name but without filename attribute. The Yahoo works fine if the filename attribute is set but C# library don't use this.
That's the header generated by C# for attachments:
Content-Type: application/octet-stream; name=test.pdf
That's the header that works with Yahoo:
Content-Type: application/octet-stream; name=file2; filename=test.pdf
Anyone get this problem so far? Is there a work arround for C# default mail sending?
using (var message = new MailMessage("from#domain", "to#yahoo.com.br", "Test with attachment", "Test with attachment"))
{
var attachment = new Attachment(#"c:\temp\test.pdf"); // Same result using stream instead path to file.
attachment.Name = "test.pdf"; // Same result without this line.
message.Attachments.Add(attachment);
using (var smtp = new SmtpClient("smtp.domain", 587))
{
smtp.Credentials = new NetworkCredential("from#domain", "password");
smtp.Send(message);
}
}

I found a solution:
attachment.ContentDisposition.FileName = "test.pdf";
This add the missing filename attribute in the raw e-mail message and solve the Yahoo limitation.

Have you tried explicitly specifying the content type?
var attachment = new Attachment(... , MediaTypeNames.Application.Octet);

Related

Illegal characters in the path

I'm trying to send mail with attachments using smtp client.
Everything goes well when I'm trying to add an attachment like that:
System.Net.Mail.Attachment attachment;
attachment = new System.Net.Mail.Attachment(#"C:\icon.jpg");
mail.Attachments.Add(attachment);
but when I try to read a path from the console like:
string path = Console.Read();
System.Net.Mail.Attachment attachment;
attachment = new System.Net.Mail.Attachment(path);
mail.Attachments.Add(attachment);
I'm getting the exception
Illegal charcters in the path
Is there anyone who could explain to me why it doesn't work?
The problem with your code is that Console.Read() function is intended to read only the next character from the input.
You should use Console.ReadLine() instead, which will read an entire line from the input.
string path = Console.ReadLine();
System.Net.Mail.Attachment attachment;
attachment = new System.Net.Mail.Attachment(path);
mail.Attachments.Add(attachment);

SendGrid - Image not showing up in HTML email

I am using the SendGrid v3 API and C# library (v7) to send an email.
In my email I have a header which is a png. The header is embedded like this:
<img src="cid:emailheader"/>
In the C# code I send the image as an attachment with with the same ContentId
var mail = new Mail(from, subject, to, content);
var headerPath = HttpContext.Current.Server.MapPath("~/Resources/email-header.png");
var attachment = new SendGrid.Helpers.Mail.Attachment();
attachment.ContentId = "emailheader";
attachment.Content = Convert.ToBase64String(File.ReadAllBytes(headerPath));
attachment.Type = "image/png";
attachment.Filename = "email-header.png";
mail.AddAttachment(attachment);
var send = sg.client.mail.send.post(requestBody: mail.Get());
Yet when I open the email it says the source is not found, even though the image is correctly displayed in the attachment
I'm not the expert for Sendgrid, but I found on there blog post
that this suggest to do inline encoding in your html directly. this way you don't need to add an attachment. (I'm use this quite a lot)
<img alt="My Image" src="data:image/jpeg;base64,/9j/4S/+RXhpZgAATU0AKgA...more encoding" />
Maybe this is a work around for you.
As an second alternative:
for sending out emails with pictures I'm using
System.Net.Mail
here I do add an AlternateView with a linked resource.
AlternateView htmlView = AlternateView.CreateAlternateViewFromString(html, null, "text/html");
LinkedResource imageResource = new LinkedResource(Imagepath + "Monitoring.png", "image/png")
{
ContentId = "1",
TransferEncoding = System.Net.Mime.TransferEncoding.Base64
};
htmlView.LinkedResources.Add(imageResource);
message.AlternateViews.Add(htmlView);
the syntax in html is the same as you use
<img src="cid:1">
I hope this help.
Butti
node
//imageData= "data:image/png;base64,ine793nfdsf......."
imageb64 = imageData.replace('data:image/png;base64,' , '');
//remove data:image/png;base64,
const msg = {
to: 'example#gmail.com',
from: 'test#gmail.com',
subject: "image attached",
html :'<img src="cid:myimagecid"/>',
attachments: [
{
filename: "imageattachment.png",
content: imageb64,
content_id: "myimagecid",
}
]
};
sgMail.send(msg);

How to send a iCal invite with Mailgun Rest API (C#)

I am attempting to add a calendar invite in iCal format to an email sent via the MailGun API. This is what i have so far:
var request = new RestRequest();
request.AddParameter("domain", this.domain, ParameterType.UrlSegment);
request.Resource = "{domain}/messages";
request.AddParameter("from", contactDetails.SenderAddress);
request.AddParameter("to", contactDetails.RecipientAddress);
request.AddParameter("subject", message.Subject);
request.AddParameter("text", message.TextBody);
request.AddParameter("html", message.HtmlBody);
if (!string.IsNullOrWhiteSpace(message.IcalAttachment))
{
request.AddFileBytes("attachment",
Encoding.UTF8.GetBytes(message.IcalAttachment),
"invite.ics",
"text/calendar");
}
request.Method = Method.POST;
return request;
This results in the calendar being included in the email as an attachment, not an alternative view of the email. The attachment works fine in gmail however in Outlook it appears as an attachment file that you must first click on, then agree to adding the calendar to the Outlook calendar. Is there another way to use the REST api so that the calendar invites are sent correctly, as alternative email views?
To be clear, this is how I would send a calendar invite using .Net SmtpClient:
var contentType = new ContentType("text/calendar");
if (contentType.Parameters != null)
{
contentType.Parameters.Add("method", "REQUEST");
contentType.CharSet = "UTF-8";
}
// this is the same way you add a html view to the message
request.AlternateViews.Add(
AlternateView.CreateAlternateViewFromString(
message.IcalAttachment,
contentType));
Special thanks to Mailgun support for pointing me in the right direction. The relevant part or their response was:
You can use the /message.mime endpoint to construct the MIME for the calendar invite:
https://documentation.mailgun.com/api-sending.html#sending
Creating a mime message isnt as easy as simply using their /message endpoint but there are several .net libraries available to do this. I used MimeKit in this example.
var request = new RestRequest();
request.AddParameter("domain", this.domain, ParameterType.UrlSegment);
request.Resource = "{domain}/messages.mime";
request.AddParameter("to", contactDetails.RecipientAddress);
request.AddFile(
"message",
Encoding.UTF8.GetBytes(BuildMimeContent(message)),
"message.mime");
request.Method = Method.POST;
return request;
The mime content that I want to create will contain a multipart/mixed body, which will in turn contain a multipart/alternative as well as every attachment. The calendar invite will actually be attached twice, as a alternative view and as an attachment. This is to aid in compatibilitiy across different email clients.
The implementation of BuildMimeContent(message) looks like the following:
// create the alternative views
var textBody = new TextPart("plain") { Text = message.TextBody };
var htmlBody = new TextPart("html") { Text = message.HtmlBody };
// add views to the multipart/alternative
var alternative = new Multipart("alternative");
alternative.Add(textBody);
alternative.Add(htmlBody);
if (!string.IsNullOrWhiteSpace(message.CalendarInvite))
{
// also add the calendar as an alternative view
// encoded as base64, but 7bit will also work
var calendarBody = new TextPart("calendar")
{
Text = message.CalendarInvite,
ContentTransferEncoding = ContentEncoding.Base64
};
// most clients wont recognise the alternative view without the
// method=REQUEST header
calendarBody.ContentType.Parameters.Add("method", "REQUEST");
alternative.Add(calendarBody);
}
// create the multipart/mixed that will contain the multipart/alternative
// and all attachments
var multiPart = new Multipart("mixed") { alternative };
if (!string.IsNullOrWhiteSpace(message.CalendarInvite))
{
// add the calendar as an attachment
var calAttachment = new MimePart("application", "ics")
{
ContentDisposition = new ContentDisposition(ContentDisposition.Attachment),
ContentTransferEncoding = ContentEncoding.Base64,
FileName = "invite.ics",
ContentObject = new ContentObject(GenerateStreamFromString(message.CalendarInvite))
};
multiPart.Add(calAttachment);
}
// TODO: Add any other attachements to 'multipart' here.
// build final mime message
var mimeMessage = new MimeMessage();
mimeMessage.From.Add(GetMimeAddress(message.MessageInfo.SenderName, message.MessageInfo.SenderAddress));
mimeMessage.To.Add(GetMimeAddress(message.MessageInfo.RecipientName, message.MessageInfo.RecipientAddress));
mimeMessage.Subject = message.Subject;
mimeMessage.Body = multiPart;
// parse and return mime message
return mimeMessage.ToString();
Warning for people testing with Office 365
Office365 is extremely picky when it comes to validating calendar invites. In order to not get a message like the one below, you will need to ensure that the vCal's organizer email address matches the email's from address. This is not possible if you are using mailgun's sandbox test environment.

Sign/Encrypt EDIFACT document - malformed - C#

I have to send an EDI message to a government body, which is signed/encrypted in a particular way.
According to https://docs.google.com/document/d/1xOxsZG7nCXdd3ucFKJObheW4G6kFwflGFkzURS_haTY/edit?usp=sharing
I am trying this code, but the encrypted S/MIME isn’t correctly formatted according to the government gateway.
Email reply from them:
The Error Code I am getting is a decryption failure.
You should have signed your EDI message using your Gatekeeper Certificate first.
This produces an S/MIME blob. We call this the “signed” S/MIME .
Then, you take your signed blob and encrypt it using the Customs Gateway Certificate downloaded from our cargo web site.
This produces another S/MIME, we call the “encrypted” S/MIME.
I am signing and encrypting using the correct encryption certificates.
Have also tried 3rd party libraries ActiveUp and Chilkat to no avail so far.
Any help in interpreting the Customs Spec and adjusting where I might have gone wrong much appreciated. I have been working on this issue for more than a week.
public static void SendEmail(string ediMsg, string clientCertificatePath,
string clientCertificatePassword, string sender, string receiver, string subject, SmtpClient smtp,
string customsCertificatePath)
{
//Load the certificate
X509Certificate2 EncryptCert = new X509Certificate2(customsCertificatePath);
X509Certificate2 SignCert =
new X509Certificate2(clientCertificatePath, clientCertificatePassword);
//Build the body into a string
StringBuilder Message = new StringBuilder();
ediMsg = "UNB+IATB:1+6XPPC+LHPPC+940101:0950+1' ...";
/*The EDI document is first formatted as a MIME message [MIME],
* as the EDI Document may contain special characters, non-printable ASCII and binary data. */
byte[] arrayToEncode = System.Text.Encoding.UTF8.GetBytes(ediMsg);
ediMsg = Convert.ToBase64String(arrayToEncode);
/*Within the MIME message, the Content-Transfer-Encoding header must be either “quoted-printable”
* or “base64”, and the Content-Type header should be set to “Application/EDIFACT”. */
Message.AppendLine("Content-Type: Application/EDIFACT");
Message.AppendLine("Content-Transfer-Encoding: base64");
//The file name of the attachment for inbound e-mails (to Customs) must be the same as the Subject Line
//(section 3.3) with the .edi suffix.
Message.AppendLine("Content-Disposition: attachment; filename=\"" + subject + ".edi\"");
/*I have tried this with
* (a) the raw ediMsg,
* (b) the base64 version of (a)
* (c) quoted-printable version of (a)
* (d) base64 version of (c)
*/
Message.AppendLine(ediMsg);
//Text must not be included in the body of the e-mail. EDI documents must be sent as an attachment.
//Convert the body to bytes
byte[] BodyBytes = Encoding.UTF8.GetBytes(Message.ToString());
//sign
var signedBytes = SignMsg(BodyBytes, SignCert);
//Build the e-mail body bytes into a secure envelope
EnvelopedCms Envelope = new EnvelopedCms(new ContentInfo(signedBytes));
CmsRecipient Recipient = new CmsRecipient(
SubjectIdentifierType.IssuerAndSerialNumber, EncryptCert);
Envelope.Encrypt(Recipient);
byte[] EncryptedBytes = Envelope.Encode();
//Create the mail message
MailMessage Msg = new MailMessage();
Msg.To.Add(new MailAddress(receiver));
Msg.From = new MailAddress(sender);
Msg.Subject = subject;
//Attach the encrypted body to the email as and ALTERNATE VIEW
MemoryStream ms = new MemoryStream(EncryptedBytes);
AlternateView av =
new AlternateView(ms,
"application/pkcs7-mime; smime-type=signed-data;name=smime.p7m");
Msg.AlternateViews.Add(av);
//SmtpClient smtp = new SmtpClient(MailServer, 25);
//send the email
smtp.Send(Msg);
}
I'm not sure the issues I'm about to point out are the problem, but they might be worth looking into...
First, Convert.ToBase64String(arrayToEncode); does not wrap lines as needed in MIME. What you'll need to use is this variant with Base64FormattingOptions.InsertLineBreaks.
Secondly, I don't know what SignMsg() does, but make sure that you prepend the proper Content-Type, Content-Transfer-Encoding, and (possibly) Content-Disposition headers as well. The Content-Type should be application/pkcs7-mime; smime-type=signed-data; name=smime.p7s and Content-Transfer-Encoding should be base64 once you've base64 encoded the data.
Thirdly, the Content-Type header you gave to the encrypted outer part is wrong. It should be application/pkcs7-mime; smime-type=enveloped-data; name=smime.p7m.
Fourthly, Make sure that the encrypted data gets base64 encoded and that the AlternativeView gets a Content-Transfer-Encoding of base64.
I'm not sure if adding it as an alternative view will necessarily work or not, I'd have to see the generated MIME to be sure.
Something you might consider using instead of IP*Works which is payware is my Open Source library called MimeKit which already supports generating S/MIME messages. I also have a library called MailKit which supports SMTP which you seem to be using.
Both libraries are easily available via NuGet: MimeKit and MailKit
What you would do is something like this:
// Note: if the email addresses do not match the certificates, you can
// use a SecureMailboxAddress instead, which allows you to specify the
// Fingerprint (aka Thumbprint) of the certificate to use for signing
// or encrypting.
var recipient = new MailboxAddress ("Receiver Name", "receiver#example.com");
var sender = new MailboxAddress ("Sender Name", "sender#example.com");
var message = new MimeMessage ();
message.To.Add (recipient);
message.From.Add (sender);
message.Subject = subject;
// create the application/edifact MIME part
var edifact = new MimePart ("application", "edifact");
// set the filename of the MIME part (adds a Content-Disposition header
// if not already present)
edifact.FileName = subject + ".edi";
// create the content stream of the MIME part
var content = new MemoryStream (Encoding.UTF8.GetBytes (ediMsg), false);
// set the content of the MIME part (we use ContentEncoding.Default because
// it is not encoded... yet)
edifact.ContentObject = new ContentObject (content, ContentEncoding.Default);
// encode the content using base64 *and* set the Content-Transfer-Encoding header
edifact.ContentTransferEncoding = ContentEncoding.Base64;
using (var ctx = new TemporarySecureMimeContext ()) {
ctx.Import (clientCertificatePath, clientCertificatePassword);
ctx.Import (customsCertificatePath);
// sign and then encrypt the edifact part and then set the result as the
// message body.
message.Body = ApplicationPkcs7Mime.SignAndEncrypt (ctx, sender,
DigestAlgorithm.Sha1, new [] { recipient }, edifact);
}
// MailKit's SMTP API is very similar to System.Net.Mail's SmtpClient API,
// so that shouldn't pose a problem.

SMTP Permission Error

I'm using system.net.mail and have a textbox that users can enter their email address and a file gets attached and sent to them. When I test this in my custom box with Server 2008 I get the following error:
Request for the permission of type 'System.Net.Mail.SmtpPermission....at System.Security.CodeAccessSecurityEngine.Check
Do I have to configure something specifically on the server to allow? Or is it a code error?
string strto = txtTo.Text;
//create the mail message
MailMessage mail = new MailMessage();
//set the addresses
mail.From = new MailAddress("serveremail");
mail.To.Add(strto);
//set the content
mail.Subject = "subject";
//Get some binary data
byte[] byteArray = Encoding.ASCII.GetBytes(result);
//save the data to a memory stream
using (MemoryStream ms = new MemoryStream(byteArray))
//create the attachment from a stream. Be sure to name the data with a file and
//media type that is respective of the data
mail.Attachments.Add(new Attachment(ms, "test.txt", "text/plain"));
//send the message
SmtpClient smtp = new SmtpClient("server");
smtp.Send(mail);
This looks like it could be a permission issue when trying to access the attachment from the steam. What happens if you explicitly state credentials?

Categories