Rails 4/5发送动态ActionMailer :: Base.mail电子邮件附件标记为Noname

时间:2016-10-13 13:29:53

标签: ruby-on-rails excel email ruby-on-rails-4

我已经看过类似的帖子,主要是通过创建视图和控制器来发送附件,例如:

PDF attachment in email is called 'Noname'

但是我有一个动态生成后台文件的进程,需要使用ActionMailer :: Base.mail将其附加到收件人列表。以下是代码:

def send_email(connection)
    email = ActionMailer::Base.mail(to: connection['to'], from: connection['from'], subject: 'Sample File', body: "<p>Hello,</p><p>Your data is ready</p>", content_type: 'multipart/mixed')
    email.cc = connection['cc'] if connection['cc'].present?
    email.bcc = connection['bcc'] if connection['bcc'].present?
    @files.each do |file|
      report_file_name = "#{@start_time.strftime('%Y%M%dT%I%m%s')}_#{file[0]}.xlsx"
      file_location = "#{Rails.root}/tmp/#{report_file_name}"
      email.attachments[report_file_name] = File.open(file_location, 'rb'){|f| f.read}
    end
    email.deliver if email
  end

我可以在日志中看到它与内容一起发送,但假设它发送为Noname,因为它无法找到该视图。有什么方法可以让它成功运作?

以下是示例输出:

  

发送邮件至sample@sample.com(383.9ms)日期:   2016年10月13日星期四08:47:30 -0400来自:样品到:   收件人消息ID:   &LT; 57ff326270f15_421f1173954919e2@ulinux.mail>主题:样本文件   Mime版本:1.0内容类型:multipart / mixed;字符集= UTF-8   内容传输编码:7位

     

- Content-Type:application / vnd.openxmlformats-officedocument.spreadsheetml.sheet;   文件名= 20161012T08101476259208_Data.xlsx   Content-Transfer-Encoding:base64 Content-Disposition:attachment;   filename = 20161012T08101476259208_Data.xlsx Content-ID:   &LT; 57ff326270f15_421f1173954919e2@ulinux.mail>

     

UEsDBBQAAAAIAO ...... ...... ADUFQAAAAA =

更新 - 我注意到我是否使用了email.content_type =&#39; text / plain&#39; - 附件成功通过。对我来说,这是有效的,尽管我以后能够用HTML格式化我的电子邮件

我认为这是有效的,因为它阻止了Rails通常的收集/自动解释过程。我当然希望看到多部分/混合或HTML兼容版本在这里工作。

更新2 这只会在rails_email_preview gem中人为地修复此问题,这会将电子邮件呈现为开发中的新标签。在制作中,这简单且可以理解地打印出细节和大概是base64编码的文件,所以问题仍然存在。

1 个答案:

答案 0 :(得分:0)

我也遇到了这个问题,经过一些调查后,在Rails 4中,您在调用邮件方法后无法调用附件方法,否则邮件消息对象的content_type不具有边界信息,因此无法在接收的电子邮件中正确解析附件部分。

我认为深入研究动作管理器源代码,您应该能够通过覆盖默认的邮件方法或手动设置正确的边界信息来找到解决方案。

但是为了快速解决这个问题,我通过使用元编程思考了一个不优雅的工作:定义一个继承ActionMailer :: Base的委托类。

class AnyMailer < ActionMailer::Base
  # a delegation mailer class used to eval dynamic mail action
end

然后通过定义执行电子邮件发送的任意方法来评估此类。

def send_email(connection, files)
  AnyMailer.class_eval do
    def any_mailer(connection, files)
      files.each do |file|
        report_file_name = :foo
        file_location = :bar
        attachments[report_file_name] = File.open(file_location, 'rb'){|f| f.read}
      end
      mail(to: connection['to'], from: connection['from'], subject: 'Sample File', body: "<p>Hello,</p><p>Your data is ready</p>")
    end
  end

  AnyMailer.any_mailer(connection, files).deliver_now
end

注意,您不需要将content_type指定为&#39; multipart / mixed&#39;,ActionMailer将正确处理它。我尝试明确地指定它,但却搞砸了电子邮件内容。