如何通过电子邮件发送Excel文件?

时间:2012-11-04 21:39:30

标签: c# excel email attachment

我有一个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文件?

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

5 个答案:

答案 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;
    }
}

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

答案 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