C# 如何通过电子邮件发送 Excel 文件?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/13223200/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How can I send an Excel file by email?
提问by ZYD
I have an excel file (Excel 2003 / xls format) and I want to send it by email with c#. My code send it successfully, but when I try to open the response file, it seems to encoded wrongly.
我有一个 excel 文件(Excel 2003 / xls 格式),我想用 c# 通过电子邮件发送它。我的代码发送成功,但是当我尝试打开响应文件时,它似乎编码错误。
For example here is the response filename:
例如这里是响应文件名:
=_utf-8_B_RWxzesOhbW9sw6FzXzIwMTJfMTBfMTZf.dat
=_utf-8_B_RWxzesOhbW9sw6FzXzIwMTJfMTBfMTZf.dat
And here is the response file itself:
这是响应文件本身:
=?utf-8?B?VEdWdmJIWmhjMkZ1Wk1Pelh6UXlYekZmPz0NCiA9P3V0Zi04P0I/VGtW?=\ \ =?utf-8?B?TlgwZFRXaTU0YkhNPT89?=" Content-Transfer-Encoding: base64 Content-Disposition: attachment
0M8R4KGxGuEAAAAAAAAAAAAAAAAAAAAAPgADAP7/CQAGAAAAAAAAAAAAAAABAAAA AQAAAAAAAAAAEAAAIwAAAAEAAAD+////AAAAAAAAAAD///////////////////// //////////////////////////////////////////////////////////////// ////////////////////////////// ....
=?utf-8?B?VEdWdmJIWmhjMkZ1Wk1Pelh6UXlYekZmPz0NCiA9P3V0Zi04P0I/VGtW?=\ =?utf-8?B?TlgwZFRXaTU0YkhNPT89?="Content-Transfer-Encoding-:Dis base-Transfer-Encoding
0M8R4KGxGuEAAAAAAAAAAAAAAAAAAAAAPgADAP7/CQAGAAAAAAAAAAAAAAABAAAA AQAAAAAAAAAAEAAAIwAAAAAAAAD+////AAAAAAAAAD////////////////////////////////////// //////////////////////////////////////////////// //////////////////////// ....
Here is my code fragment:
这是我的代码片段:
...
var attachment = new Attachment(WriteFileToMemory("fileFullPath"), "fileName.xls");
attachment.ContentType = new ContentType("application/vnd.ms-excel");
attachmentCollection.Add(attachment);
...
private Stream WriteFileToMemory(string filePath)
{
var memoryStream = new MemoryStream();
_openedStreams.Add(memoryStream);
using (var file = new FileStream(filePath, FileMode.Open, FileAccess.Read))
{
var bytes = new byte[file.Length];
file.Read(bytes, 0, (int) file.Length);
memoryStream.Write(bytes, 0, (int) file.Length);
file.Close();
}
memoryStream.Position = 0;
return memoryStream;
}
How can I set the attachment encoding type, and which encoding should I use with Excel files?
如何设置附件编码类型,以及我应该对 Excel 文件使用哪种编码?
Please help me solve this problem. Thanks in advance.
请帮我解决这个问题。提前致谢。
采纳答案by ZYD
I found a solution:
我找到了一个解决方案:
...
var attachment = CreateAttachment(WriteFileToMemory(Common.TempPath + excelName), excelName);
attachmentCollection.Add(attachment);
...
private Stream WriteFileToMemory(string filePath)
{
var fileStream = new FileStream(filePath, FileMode.Open, FileAccess.Read);
_openedStreams.Add(fileStream);
return fileStream;
}
public static Attachment CreateAttachment(Stream attachmentFile, string displayName)
{
var attachment = new Attachment(attachmentFile, displayName);
attachment.ContentType = new ContentType("application/vnd.ms-excel");
attachment.TransferEncoding = TransferEncoding.Base64;
attachment.NameEncoding = Encoding.UTF8;
string encodedAttachmentName = Convert.ToBase64String(Encoding.UTF8.GetBytes(displayName));
encodedAttachmentName = SplitEncodedAttachmentName(encodedAttachmentName);
attachment.Name = encodedAttachmentName;
return attachment;
}
private static string SplitEncodedAttachmentName(string encoded)
{
const string encodingtoken = "=?UTF-8?B?";
const string softbreak = "?=";
const int maxChunkLength = 30;
int splitLength = maxChunkLength - encodingtoken.Length - (softbreak.Length * 2);
IEnumerable<string> parts = SplitByLength(encoded, splitLength);
string encodedAttachmentName = encodingtoken;
foreach (var part in parts)
{
encodedAttachmentName += part + softbreak + encodingtoken;
}
encodedAttachmentName = encodedAttachmentName.Remove(encodedAttachmentName.Length - encodingtoken.Length, encodingtoken.Length);
return encodedAttachmentName;
}
private static IEnumerable<string> SplitByLength(string stringToSplit, int length)
{
while (stringToSplit.Length > length)
{
yield return stringToSplit.Substring(0, length);
stringToSplit = stringToSplit.Substring(length);
}
if (stringToSplit.Length > 0)
{
yield return stringToSplit;
}
}
Based on this source:http://social.msdn.microsoft.com/Forums/en-US/dotnetframeworkde/thread/b6c764f7-4697-4394-b45f-128a24306d55
基于此来源:http : //social.msdn.microsoft.com/Forums/en-US/dotnetframeworkde/thread/b6c764f7-4697-4394-b45f-128a24306d55
回答by flindeberg
You are making it too complex, as @Magnus points out, new Attachment()can handle FileStreams so just pass a new filestream to the constructor.
正如@Magnus 指出的那样,你让它太复杂了,new Attachment()可以处理FileStreams 所以只需将一个新的文件流传递给构造函数。
...
var attachment = new Attachment(File.Open("fileFullPath", FileMode.Open), "fileName.xls");
attachment.ContentType = new ContentType("application/vnd.ms-excel");
attachmentCollection.Add(attachment);
...
A word of warning though, kind is off topic, you cannot send a mail like that multiple times since the stream will not always reset itself properly.
警告的话,种类是题外话,你不能多次发送这样的邮件,因为流不会总是正确地重置自己。
回答by Alexander Reva
An email message attachment name that contains non-ASCII characters and is longer than 41 UTF-8 encoded bytes is encoded two times before transmission in an application that is compiled for the .NET Framework 4. This problem occurs because of an issue in the .NET Framework 4. The SMTP encodings were rewritten to include correct folding per RFC standards of line-length limits. This behavior inserts additional carriage return line feed (CRLF) characters when the name string is too long. These additional control characters cause the attachment name to be encoded again. More you can find here http://support.microsoft.com/kb/2402064
包含非 ASCII 字符且长度超过 41 个 UTF-8 编码字节的电子邮件附件名称在为 .NET Framework 4 编译的应用程序中传输之前被编码两次。 出现此问题的原因是 . NET Framework 4. SMTP 编码被重写,以包括每个 RFC 标准的行长度限制的正确折叠。当名称字符串太长时,此行为会插入额外的回车换行 (CRLF) 字符。这些额外的控制字符会导致附件名称再次被编码。您可以在此处找到更多信息http://support.microsoft.com/kb/2402064
回答by Roman
I'm resolving the same problem by correcting MailMessage properties:
我正在通过更正 MailMessage 属性来解决同样的问题:
bool SendEmail(string subject, string message, Attachment attachment)
{
try
{
SmtpClient smtpClient = CreateProductionSMTPClient();
MailMessage msg = new MailMessage();
msg.Subject = subject;
msg.Body = message;
msg.To.Add(ConfigurationHelper.EmailTo);
msg.From = new MailAddress(ConfigurationHelper.EmailFrom);
msg.BodyEncoding = Encoding.UTF8;
//commented line cause the problem
// msg.Headers.Add("Content-Type", "text/html");
//instead of that use next line
msg.IsBodyHtml = true;
if (attachment != null)
{
msg.Attachments.Add(attachment);
}
smtpClient.Send(msg);
return true;
}
catch (Exception ex)
{
return false;
}
}
//Attachment building
Attachment WrapExcelBytesInAttachment(byte[] excelContent)
{
try
{
Stream stream = new MemoryStream(excelContent);
Attachment attachment = new Attachment(stream, "fileName.xls");
attachment.ContentType = new ContentType("application/vnd.ms-excel");
return attachment;
}
catch (Exception ex)
{
return null;
}
}
回答by Víctor Beltrán
In case you want to generate Excel from a DataTable, and send it by mail, you can attach the excel file as follows:
如果您想从 DataTable 生成 Excel 并通过邮件发送,您可以按如下方式附加 Excel 文件:
Workbook theWorkbook = new Workbook();
theWorkbook.SetCurrentFormat(WorkbookFormat.Excel2007);
Worksheet theWorkSheet = theWorkbook.Worksheets.Add("Sheet1");
int iRow = 0;
int iColumn = 0;
theWorkSheet.Rows[0].CellFormat.Font.Bold = ExcelDefaultableBoolean.True;
//Titles
foreach (DataColumn column in DataTable.Columns)
{
theWorkSheet.Rows[iRow].Cells[iColumn].Value = column.ColumnName;
iColumn++;
}
//Values
foreach (DataRow row in DataTable.Rows)
{
iColumn = 0;
iRow++;
foreach (var item in row.ItemArray)
{
theWorkSheet.Rows[iRow].Cells[iColumn].Value = item.ToString();
iColumn++;
}
}
System.IO.MemoryStream theStream = new System.IO.MemoryStream();
theWorkbook.Save(theStream);
byte[] byteArr = theStream.ToArray();
System.IO.MemoryStream stream1 = new System.IO.MemoryStream(byteArr, true);
stream1.Write(byteArr, 0, byteArr.Length);
stream1.Position = 0;
message.Attachments.Add(new Attachment(stream1, "filename.xlsx"));
It worked for me at least with .NET framework 4 and Excel 2016.
它至少适用于 .NET framework 4 和 Excel 2016。
Regards.
问候。

