9

我有一个 excel 文件(Excel 2003 / xls 格式),我想用 c# 通过电子邮件发送它。我的代码发送成功,但是当我尝试打开响应文件时,它似乎编码错误。

例如这里是响应文件名:

=_utf-8_B_RWxzesOhbW9sw6FzXzIwMTJfMTBfMTZf.dat

这是响应文件本身:

=?utf-8?B?VEdWdmJIWmhjMkZ1Wk1Pelh6UXlYekZmPz0NCiA9P3V0Zi04P0I/VGtW?=\ \ =?utf-8?B?TlgwZFRXaTU0YkhNPT89?=" 内容传输编码:base64 内容处置:附件

0M8R4KGxGuEAAAAAAAAAAAAAAAAAAAAAAAPgADAP7/CQAGAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAEAAAAWAAAAEAAAD+////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 文件使用哪种编码?

请帮我解决这个问题。提前致谢。

4

5 回答 5

6

正如@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);
...

警告一句,kind 是题外话,你不能多次发送这样的邮件,因为流不会总是正确地重置自己。

于 2012-11-05T08:19:37.827 回答
5

如果您想从 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 框架 4 和 Excel 2016。

问候。

于 2017-07-27T10:43:34.863 回答
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;
    }
}

基于此来源: http ://social.msdn.microsoft.com/Forums/en-US/dotnetframeworkde/thread/b6c764f7-4697-4394-b45f-128a24306d55

于 2012-11-10T17:40:16.863 回答
1

包含非 ASCII 字符且长度超过 41 个 UTF-8 编码字节的电子邮件附件名称在传输之前在为 .NET Framework 4 编译的应用程序中被编码两次。出现此问题的原因是 . NET Framework 4。重写了 SMTP 编码,以包括根据 RFC 标准的行长限制正确折叠。当名称字符串太长时,此行为会插入额外的回车换行符 (CRLF) 字符。这些额外的控制字符会导致附件名称再次被编码。更多您可以在这里找到http://support.microsoft.com/kb/2402064

于 2013-01-09T19:32:28.230 回答
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;
    }
}
于 2013-02-12T19:15:01.440 回答