Asp.net/C# 在多个电子邮件下载时附加标头错误

Asp.net/C# append header error on mutliple email downloads

提问人:toiletboss 提问时间:8/11/2022 更新时间:8/12/2022 访问量:96

问:

我有一个 asp.net/c# 应用程序,它有一个功能,用户可以触发它是什么,然后下载一封电子邮件。如果有一封电子邮件被触发/下载,那完全可以正常工作。但是,如果有多封电子邮件,我会收到“发送 HTTP 标头后服务器无法追加标头”错误。我搞砸了,做了一些谷歌 fu,但似乎没有任何效果。

生成第一封电子邮件后,它会在“Response.AddHeaders”行上出错。

public void EmailDownload(string toAddress, string ccAddress, string subject, string body, string downloadName)
    {
        var assembly = typeof(SmtpClient).Assembly;
        var mailWriterType = assembly.GetType("System.Net.Mail.MailWriter");

        using (MemoryStream stream = new MemoryStream())
        {

            MailMessage message = new MailMessage();
            message.Body = body;
            //message.To.Add(new MailAddress(toAddress));
            message.To.Add(new MailAddress(emailAddress);

            if (!string.IsNullOrEmpty(ccAddress))
            {
                message.CC.Add(new MailAddress(ccAddress));
            }
            //message.From = new MailAddress("[email protected]");
            message.From = new MailAddress(emailAddress);
            message.Subject = subject;
            message.Headers.Add("X-Unsent", "1");
            message.IsBodyHtml = true;

            // Get reflection info for MailWriter contructor
            var mailWriterContructor = mailWriterType.GetConstructor(BindingFlags.Instance | BindingFlags.NonPublic, null, new[] { typeof(Stream) }, null);

            // Construct MailWriter object with our FileStream
            var mailWriter = mailWriterContructor.Invoke(new object[] { stream });

            // Get reflection info for Send() method on MailMessage
            var sendMethod = typeof(MailMessage).GetMethod("Send", BindingFlags.Instance | BindingFlags.NonPublic);

            // Call method passing in MailWriter
            sendMethod.Invoke(message, BindingFlags.Instance | BindingFlags.NonPublic, null, new[] { mailWriter, true, true }, null);

            // Finally get reflection info for Close() method on our MailWriter
            var closeMethod = mailWriter.GetType().GetMethod("Close", BindingFlags.Instance | BindingFlags.NonPublic);

            // Call close method
            closeMethod.Invoke(mailWriter, BindingFlags.Instance | BindingFlags.NonPublic, null, new object[] { }, null);

            byte[] data = stream.ToArray();
            stream.Close();
            Response.Clear();
            Response.ContentType = "application/force-download";
            Response.AddHeader("content-disposition", "attachment;    filename=" + downloadName + ".eml");
            Response.BinaryWrite(data);
            //Response.End();
            Response.Flush();
            Response.SuppressContent = true;
            HttpContext.Current.ApplicationInstance.CompleteRequest();
        }
    }
C# asp.net 电子邮件

评论


答:

0赞 Albert D. Kallal 8/12/2022 #1

您只能有一个页面响应来发送文件。执行此操作后,所有代码都将终止。

我不相信您可以一次发送/拥有多个页面的回复。您创建一个响应并发送它 - 您的代码现在在该时间点终止。

这建议,如果您希望用户获取/抓取/拥有多个文件,那么您需要一个 UI,如下所示:

enter image description here

标记是一个网格视图,我们有一个简单的 asp.net 按钮。所以这个:

标记:

        <asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="false" CssClass="table">
            <Columns>
                <asp:BoundField DataField="File Name" HeaderText="File"  />
                <asp:BoundField DataField="Date" HeaderText="Date" />
                <asp:BoundField DataField="File Size" HeaderText="Size" />
                <asp:TemplateField HeaderText="Select"  ItemStyle-HorizontalAlign="Center">
                    <ItemTemplate>
                        <asp:Button ID="cmdDownLoad" runat="server" Text="Download" cssclass="btn"
                            OnClick="cmdDownLoad_Click" />
                    </ItemTemplate>
                </asp:TemplateField>
            </Columns>
        </asp:GridView>

和按钮代码:

   protected void cmdDownLoad_Click(object sender, EventArgs e)
    {
        Button btn = sender as Button;
        GridViewRow gRow = btn.NamingContainer as GridViewRow;

        string sFileOnly = gRow.Cells[0].Text;
        string sFile = Server.MapPath("~/Content/Animals/" + sFileOnly);

        string sMineType = MimeMapping.GetMimeMapping(sFile);

        Response.ContentType = sMineType;
        Response.AppendHeader("Content-Disposition", "attachment; filename=" + sFileOnly);
        Response.TransmitFile(sFile);
        Response.End();

    }

事实上,如果我把代码放在响应结束之后,可以这样说:

    Response.ContentType = sMineType;
        Response.AppendHeader("Content-Disposition", "attachment; filename=" + sFileOnly);
        Response.TransmitFile(sFile);
        Response.End();

        Debug.Print("code runs after above");

调试打印代码从不运行,因为我必须使用 response.end 来发送一个文件。一旦你这样做了 - 所有代码都会终止。

因此,您必须显示/提供电子邮件列表,并为用户提供一个按钮或一些按钮来下载每个文件。因此,您可以在代码中创建一个表,甚至创建一个 ListItem,并将其发送到网格。

并假设每次单击按钮都是一次回发,那么您必须将电子邮件列表保留在视图状态或会话中,以便在该网格中显示。您可以构建一个列表结构,将其传递给网格,因此 GV 将为您保留列表(请参阅我如何从上面的 GV 中获取文件)。

评论

0赞 toiletboss 8/12/2022
感谢您的深入回应!我将努力实现这一点,并让你知道!谢谢!