我有一个excel文件(Excel 2003 / xls格式),我想通过电子邮件用c#发送它。 我的代码成功发送,但是当我尝试打开响应文件时,它似乎编码错误。
例如,这里是响应文件名:
= _ UTF-8_B_RWxzesOhbW9sw6FzXzIwMTJfMTBfMTZf.dat
这是响应文件本身:
=?UTF-8 2 B 4 VEdWdmJIWmhjMkZ1Wk1Pelh6UXlYekZmPz0NCiA9P3V0Zi04P0I / VGtW?= \ \ =?utf-8?B?TlgwZFRXaTU0YkhNPT89?=“Content-Transfer-Encoding:base64 内容处理:附件
0M8R4KGxGuEAAAAAAAAAAAAAAAAAAAAAPgADAP7 / CQAGAAAAAAAAAAAAAAABAAAA AQAAAAAAAAAAEAAAIwAAAAEAAAD + //// AAAAAAAAAAD ///////////////////// ////////////////////////////////////////////////// ////////////// ////////////////////////////// ....
这是我的代码片段:
...
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;
}
如何设置附件编码类型,以及我应该将哪些编码用于Excel文件?
请帮我解决这个问题。 提前谢谢。
答案 0 :(得分:5)
你正在使它过于复杂,正如@Magnus指出的那样,new Attachment()
可以处理FileStream
,所以只需将新的文件流传递给构造函数。
...
var attachment = new Attachment(File.Open("fileFullPath", FileMode.Open), "fileName.xls");
attachment.ContentType = new ContentType("application/vnd.ms-excel");
attachmentCollection.Add(attachment);
...
虽然有一个警告,但是有些不合适,你不能多次发送这样的邮件,因为流不会总是正确地重置。
答案 1 :(得分:2)
如果您想从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"));
至少在.NET framework 4和Excel 2016中它对我有用。
问候。
答案 2 :(得分:1)
我找到了解决方案:
...
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;
}
}
答案 3 :(得分:1)
我正在通过更正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;
}
}
答案 4 :(得分:0)
包含非ASCII字符且长度超过41个UTF-8编码字节的电子邮件附件名称在为.NET Framework 4编译的应用程序中传输之前被编码两次。出现此问题是由于某个问题在.NET Framework 4中。重写了SMTP编码,以包括根据RFC标准的行长度限制进行正确折叠。当名称字符串太长时,此行为会插入其他回车换行符(CRLF)字符。这些附加控制字符会导致附件名称再次编码。您可以在此处找到更多http://support.microsoft.com/kb/2402064