3

I need to send some text in html by email. But I need to do it not in the email body but in the attachment. I use this code snippet to form an attachment:

public MailMessage GetMailMessage(string @from)
{
  var m = new MailMessage(new MailAddress(@from), new MailAddress(_to)) {Subject = _subj};
  var attach = new Attachment(new MemoryStream(
       Encoding.UTF8.GetBytes(_htmlAttach)), _subj + ".html", MediaTypeNames.Text.Html);
  attach.ContentDisposition.Inline = false;
  attach.ContentType.Name = _subj + ".html";
  m.Attachments.Add(attach);
  return m;
}

But when I send such an email to my gmail mailbox i recieve a plain-text message with smth like this in text:

\ =?utf-8?B?dDlDd0lOQy8wTFhSZ05DNDBMN1F0Q0F4Pz0NCiA9P3V0Zi04P0I/TXpv?=\ \ =?utf-
8?B?ME5pQXlPUzR3T0M0eU1ERXhJQzBnTVRRNk1qQWdNamt1TURndU1qQXhN?=\ \ =?utf-8?B?UzVvZEcxcz89?=" 
Content-Transfer-Encoding: base64 Content-Disposition: attachment 
PCFET0NUWVBFIGh0bWwgUFVCTElDICItLy9XM0MvL0RURCBIVE1MIDQuMDEvL0VO 
IiAiaHR0cDovL3d3dy53My5vcmcvVFIvaHRtbDQvc3RyaWN0LmR0ZCI+DQo8aHRt 
bCB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94aHRtbCIgeG1sOmxhbmc9 ImVuIj4NCjxoZWFkPg0KI

What is the right way to send a html-file in attach?


UPD:Here is the raw mail message part:

MIME-Version: 1.0
From: <xxx@xxx.xx>
To: xxx@gmail.com
Date: Mon, 29 Aug 2011 03:29:05 -0700 (PDT)
Subject: xxx
Content-Type: multipart/mixed; boundary=--boundary_0_c99e5172-1766-4cfe-a6e0-7f6b0fa11061
----boundary_0_c99e5172-1766-4cfe-a6e0-7f6b0fa11061
Content-Type: text/plain; charset=us-ascii
Content-Transfer-Encoding: quoted-printable


----boundary_0_c99e5172-1766-4cfe-a6e0-7f6b0fa11061
Content-Type: text/html;
name="=?utf-8?B?PT91dGYtOD9CPzBLUFFzdEMxMExUUXZ0QzgwTHZRdGRDOTBMalF0U0RR?=\
\

 =?utf-8?B?dDlDd0lOQy8wTFhSZ05DNDBMN1F0Q0F4Pz0NCiA9P3V0Zi04P0I/TXpv?=\
\

 =?utf-8?B?ME5pQXlPUzR3T0M0eU1ERXhJQzBnTVRRNk1qQWdNamt1TURndU1qQXhN?=\
\
 =?utf-8?B?UzVvZEcxcz89?="
Content-Transfer-Encoding: base64
Content-Disposition: attachment

Then goes the base64 text:

PCFET0NUWVBFIGh0bWwgUFVCTElDICItLy9XM0MvL0RURCBIVE1MIDQuMDEvL0VO
IiAiaHR0cDovL3d3dy53My5vcmcvVFIvaHRtbDQvc3RyaWN0LmR0ZCI+DQo8aHRt
bCB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94aHRtbCIgeG1sOmxhbmc9
ImVuIj4NCjxoZWFkPg0KICAgIDxtZXRhIGNvbnRlbnQ9InRleHQvaHRtbDsgY2hh

And in the end:

----boundary_0_c99e5172-1766-4cfe-a6e0-7f6b0fa11061--
ΩmegaMan
  • 29,542
  • 12
  • 100
  • 122
Daniel Vygolov
  • 884
  • 2
  • 13
  • 26
  • The file name looks wrong. Is there really a newline after "Content-Type: text/html;"? Also the backslashes in your sample, are they literal? They shouldn't be there. Ditto for the newlines after the backslashes. And finally, the filename looks like it has been multiple passes of RFC2047 encoding; the first phrase decodes to something which starts with `=?utf-8?B?...` – tripleee Aug 30 '11 at 16:27
  • This is the **decoded** file name: `=?utf-8?B?0KPQstC10LTQvtC80LvQtdC90LjQtSDQt9CwINC/0LXRgNC40L7QtCAx?= =?utf-8?B?Mzo0NiAyOS4wOC4yMDExIC0gMTQ6MjAgMjkuMDguMjAxMS5odG1s?=` (sic!) Decoding that in turn yields `Уведомление за период 13:46 29.08.2011 - 14:20 29.08.2011.html`. You should strip the double encoding, at the very least. – tripleee Aug 31 '11 at 09:45

4 Answers4

1

Looks like you are lacking newlines between the generated parts. So you need to put in something like "To: " + newMailAddress(to) + "\n" etc. You will also need to build the container MIME structure. If you don't have any actual message, just send the HTML as a single body part, rather than as an "attachment". Something like this

From: me <self@example.net>
To: you <guy@example.com>
Subject: here
MIME-Version: 1.0
Content-type: text/html; name="=?utf-8?q?really_bewildering?=
  =?utf-8?q?_long_name.html?="
Content-Transfer-Encoding: base64
Content-Disposition: attachment; filename="=?utf-8?q?really_bewildering?=
  =?utf-8?q?_long_name.html?="

PCFET0NUWVBFIGh0bWwgUFVCTElDICItL ...

The example message you pasted, which moves wraps the body inside a single-part multipart/related structure, is completely equivalent.

I believe the filename= part in Content-Disposition is the correct place to put the file name, but for backwards compatibility with very old clients, you're best off putting it in both places.

Note the correct way of wrapping a long header line: there should not be backslashes before the newline; rather, indent the follow-on line with at least one whitespace character. There should be no empty lines in the headers (the empty line is what separates the headers from the body; so the first empty line in your erroneous headers is what pushes the rest of your headers into the body).

What's with the base64 encoding everywhere? Unless your document is heavy on 8-bit content, it's probably both smaller and easier to debug if you use quoted-printable instead. You'll notice I changed the file name to quoted-printable just to make it easier to read; you could do the same with the actual attachment's contents, too.

Update: Added Content-Disposition and file name as well as comments below sample message.

Emphasis: The immediate problem is your incorrect wrapping of the multi-line filename in the MIME headers.

tripleee
  • 175,061
  • 34
  • 275
  • 318
  • Look at the raw email message, there are newlines. I need to send an html in attachment, because it can be very big. – Daniel Vygolov Aug 30 '11 at 14:59
  • Adding more MIME structure makes the message larger, not smaller. The stuff you pasted in the question clearly lacks headers and line breaks; perhaps you need to use `\r\n` rather than just `\n` then (SMTP requires DOS-style line endings, but many MTAs will accept input with the platform's native line-ending conventions). – tripleee Aug 30 '11 at 15:16
  • Actually the filename should properly be encoded per [RFC5987](https://tools.ietf.org/html/rfc5987) but this is tangential so I'm not updating the answer. See also http://stackoverflow.com/a/6745788/874188 – tripleee Feb 09 '15 at 11:50
0

Your attachment type is funky. For someone just wanting to send UTF8 (standard text) one has to specify the attachment content type. That requires one to Stream it in, instead of passing a string.

Example With a list of html text(s)

System.Net.Mime.ContentType ct 
            = new System.Net.Mime.ContentType(System.Net.Mime.MediaTypeNames.Text.Html);

HtmlAttachments.Select( str => new Attachment(str.ToStream(), ct))
               .ToList()
               .ForEach( html => mailMessage.Attachments.Add(html));

... {Usual loading of to/from etc }

client.Send(mailMessage);

For completeness here is the ToStream extensions:

public static Stream ToStream( this string value ) => ToStream(value, Encoding.UTF8);

public static Stream ToStream( this string value, Encoding encoding )
                        => new MemoryStream(encoding.GetBytes(value ?? string.Empty));
ΩmegaMan
  • 29,542
  • 12
  • 100
  • 122
0

instead of putting the bytes into a memory stream why don't you put the text?

I think you could use another overload of new Attachment() and specify the content in another way.

if you have already a file stored somewhere you can attach the file or you can use a StreamReader / TextReader combination to make sure you push text data and not binary data into the attachmentz content.

Davide Piras
  • 43,984
  • 10
  • 98
  • 147
  • I'm using a stream because there's no other way to dynamically create the content of an attachment. Other overloads of `new Attachment()` can take content from file, not from a string. – Daniel Vygolov Aug 30 '11 at 13:55
0

Use either SevenBit (only up to 1000 characters!) or QuotedPrintable as TransferEncoding for the attachment.

Lucero
  • 59,176
  • 9
  • 122
  • 152
  • Just tried to. Still my email message is without attachment and looks like this: `\ =?utf- 8?B?dDlDd0lOQy8wTFhSZ05DNDBMN1F0Q0F4Pz0NCiA9P3 V0Zi04P0I/T0Rv?=\ \ =?utf-8?B?eU9DQXlOUzR3T0M0eU 1ERXhJQzBnTVRnNk1qZ2dNekF1TURndU1qQXhN?=\ \ =?utf- 8?B?UzVvZEcxcz89?=" Content-Transfer-Encoding: quoted-printable Content-Disposition: attachment =0D=0A=0D=0A=0D=0A =0D=0A= =0D=0A =0D=0A = =0D=0A=0D=0A =0D=0A =0D=0A =0D=0A =0D=0A = =0D=0A = =0D=0A` – Daniel Vygolov Aug 30 '11 at 14:36