如何将2sxc生成的PDF通过DNN Mail.SendMail作为附件发送?
如何将生成的PDF作为附件通过DNN Mail.SendMail发送?
要实现这个需求,我们可以通过重构PDF生成逻辑,再结合两种方案(临时文件存储发送/直接内存流发送)来完成,以下是具体实现:
第一步:重构PDF生成逻辑
首先把原Controller中生成PDF字节数组的逻辑抽离成独立方法,方便复用(既可以继续用于浏览器下载,也可以用于邮件发送):
[AllowAnonymous] public class PdfController : Custom.Hybrid.Api14 { public static string generatorUrlPrefix = "/pdf/generator"; // 抽离的PDF生成核心方法 private async Task<byte[]> GeneratePdf(int episode) { var cultureCode = CmsContext.Culture.CurrentCode.Substring(0, 2); var pdfService = CreateInstance("../Services/PdfService.cs"); var printUrl = pdfService.AddPrintToken(CmsContext.Site.Url + generatorUrlPrefix + "/document?episode=" + episode); return await pdfService.GetWebPageAsPdf(printUrl); } // 原有的浏览器下载方法(保留) [HttpGet] public async Task<dynamic> Document(int episode) { byte[] pdfStream = await GeneratePdf(episode); HttpContext.Current.Response.ContentType = "application/pdf"; HttpContext.Current.Response.AddHeader("Content-Disposition", $"filename={episode}.pdf"); HttpContext.Current.Response.BinaryWrite(pdfStream); HttpContext.Current.Response.End(); return pdfStream; } // 新增的邮件发送方法(核心) // ... 下面的方案代码放在这里 }
方案一:临时文件存储后发送(推荐,适配你提供的SendMail参数)
DNN的Mail.SendMail方法的xattachments参数接受服务器文件路径数组,所以我们可以先把PDF字节数组写入服务器临时目录,发送完成后再清理临时文件:
[HttpGet] public async Task<IActionResult> SendPdfByEmail(int episode) { // 1. 生成PDF字节数组 byte[] pdfBytes = await GeneratePdf(episode); string fileName = $"{episode}.pdf"; // 2. 写入DNN临时目录(确保权限充足) string tempDir = Path.Combine(Server.MapPath("~/App_Data/Temp"), "PdfMailAttachments"); Directory.CreateDirectory(tempDir); // 自动创建不存在的文件夹 string filePath = Path.Combine(tempDir, fileName); System.IO.File.WriteAllBytes(filePath, pdfBytes); try { // 3. 构造邮件参数 string xmailFrom = "something@test.me"; string xmailTo = "something@test.me"; string xcc = ""; string xbcc = ""; string xreplyTo = ""; string xsubject = $"第{episode}集PDF文档"; string xbody = "<p>您好,附件是您请求的PDF文档,请查收。</p>"; string[] xattachments = new[] { filePath }; // 传入临时文件路径 string xsmtpServer = ""; // 可留空,默认使用DNN后台配置的SMTP服务器 string xsmtpAuthentication = ""; string xsmtpUsername = ""; string xsmtpPassword = ""; // 4. 调用DNN发送邮件 Mail.SendMail( xmailFrom, xmailTo, xcc, xbcc, xreplyTo, MailPriority.Normal, xsubject, MailFormat.Html, System.Text.Encoding.UTF8, xbody, xattachments, xsmtpServer, xsmtpAuthentication, xsmtpUsername, xsmtpPassword, DotNetNuke.Entities.Host.Host.EnableSMTPSSL ); return Ok("邮件发送成功"); } finally { // 5. 清理临时文件(可选,根据需求决定是否保留) if (System.IO.File.Exists(filePath)) { System.IO.File.Delete(filePath); } } }
注意事项:
- 选择
~/App_Data/Temp目录是因为DNN默认给该目录分配了应用程序池的读写权限,避免权限问题; - 若需要保留PDF文件,可移除
finally块中的删除逻辑,或修改存储路径到站点的文件管理目录。
方案二:直接使用内存流发送(无需存文件)
如果不想生成临时文件,可以使用System.Net.Mail结合DNN的SMTP配置来发送,这种方式直接操作内存流:
[HttpGet] public async Task<IActionResult> SendPdfByEmailStream(int episode) { // 1. 生成PDF字节数组 byte[] pdfBytes = await GeneratePdf(episode); string fileName = $"{episode}.pdf"; // 2. 构造MailMessage并添加内存流附件 using (var mailMessage = new MailMessage()) { mailMessage.From = new MailAddress("something@test.me"); mailMessage.To.Add("something@test.me"); mailMessage.Subject = $"第{episode}集PDF文档"; mailMessage.Body = "<p>您好,附件是您请求的PDF文档,请查收。</p>"; mailMessage.IsBodyHtml = true; mailMessage.BodyEncoding = System.Text.Encoding.UTF8; // 添加内存流附件 using (var ms = new MemoryStream(pdfBytes)) { var attachment = new Attachment(ms, fileName, "application/pdf"); mailMessage.Attachments.Add(attachment); // 3. 使用DNN配置的SMTP客户端发送 using (var smtpClient = new SmtpClient()) { // 从DNN后台读取SMTP配置(无需手动填写) smtpClient.Host = DotNetNuke.Entities.Host.Host.SMTPServer; smtpClient.Port = DotNetNuke.Entities.Host.Host.SMTPPort; smtpClient.EnableSsl = DotNetNuke.Entities.Host.Host.EnableSMTPSSL; smtpClient.Credentials = new NetworkCredential( DotNetNuke.Entities.Host.Host.SMTPUsername, DotNetNuke.Entities.Host.Host.SMTPPassword ); smtpClient.Send(mailMessage); } } } return Ok("邮件发送成功"); }
优势:
- 无需生成临时文件,减少磁盘IO操作;
- 直接复用DNN后台的SMTP配置,无需手动填写服务器、账号等参数,更易维护。
内容的提问来源于stack exchange,提问作者João Gomes
相关产品推荐
相关产品推荐

