0

我想在不下载附件然后重新/附加到新电子邮件的情况下执行此操作。
这是我尝试过的:

$emailslist.each do |e|
  Mail.deliver do
    from   fromstr
    to "mailman@somedomain.com"
    subject "[Events] #{subjectstr}"

    if e.attachments.length>0
      e.attachments.each do |a| 
       add_file a
     end
   end
 end
end

#error in 'e.attachments.each'=>undefined method `attachments' for
#<TypeError: can't convert nil into String> 

编辑 我已经使用这个代码几个月了,它工作得很好。

我现在介绍的新东西就是上面的代码。

无论如何,我会根据要求粘贴整个代码。

require 'mail'

$subscribers=[]

File.new("C:/Users/j.de_miguel/Desktop/mailman.forma/subscribers2.txt",'r').each do |line| 
  line=line.sub("\n","")
  $subscribers.push(line) if line =~ /@/
end

puts $subscribers

$errorfile=File.new("C:/Users/j.de_miguel/Desktop/mailman.forma/error_log2.txt",'a+')
$errorfile.write("#{Time.now}\n")
$errorfile.flush

def deleteSubjectRecursion(subjstr)

  if subjstr =~ /(.\[FORMA 2013\])+/
    subjstr.gsub!(/.\[FORMA 2013\]/,"")
  end

  if subjstr =~ /((?i)Re: ){2,}/
    subjstr.gsub!(/((?i)Re: ){2,}/,"Re: ")
  end

  return subjstr
end

def UserIsRegistered(mailaddr)

  registered = false
  $subscribers.each{|s| registered = true if mailaddr==s}
  if registered == false
    $errorfile.write("#{Time.now} : user #{mailaddr} attempted to mailman\n")
    $errorfile.flush
  end

  return registered

end


Mail.defaults do
  retriever_method :imap, { :address    => "imap.1and1.es",
                            :port       => 143, 
                            :user_name  => "mailman@somedomain.com",
                            :password   => "xxxxxxxx",
                            :enable_ssl => false }

  delivery_method :smtp, { :address              => "smtp.1and1.es",
                           :port                 => 587,
                           :domain               => '1and1.es',
                           :user_name            => 'mailman@somaedomain.com',
                           :password             => 'xxxxxxxxxxxx',
                           :authentication       => 'plain',
                           :enable_starttls_auto => true  }
end

#$emailslist=Mail.find(keys: ['NOT','SEEN'])
$emailslist=[Mail.last]

$emailslist.each do |e|

  eplain_part = e.text_part ? e.text_part.body.decoded : nil
  ehtml_part = e.html_part ? e.html_part.body.decoded : nil

  type=e.charset
  type_plain=eplain_part ? e.text_part.charset.to_s : nil
  type_html=ehtml_part ? e.html_part.charset.to_s : nil

  bodystr= type ? e.body.decoded.to_s.force_encoding(type) : nil

  type=type ? type.to_s : type_plain
  puts type.inspect

  subjectstr=e.subject.to_s.encode(type)
  fromstr=e.from.first.to_s.encode(type)
  puts fromstr

  bodystr_plain=eplain_part ? eplain_part.force_encoding(type_plain) : nil
  bodystr_html=ehtml_part ? ehtml_part.force_encoding(type_html) : nil

  $subscribers.each do |tostr|

    puts tostr.inspect

    if (not subjectstr =~ /^\[FORMA 2013\]/  ) && (UserIsRegistered(fromstr) == true)
      subjectstr=deleteSubjectRecursion(subjectstr)

      begin
        Mail.deliver do

          from   fromstr
          to      "mailman@somedomain.com"
          bcc  tostr
          subject "[FORMA 2013] #{subjectstr}"

          if ehtml_part != nil
            html_part do
              content_type("text/html; charset=#  {type_html}")
              #content_transfer_encoding("7bit")
              body "# {bodystr_html}\nmailman@forma.culturadigital.cc para darte de baja escribe \"baja\" a info@culturadigital.cc"
            end
          end

          if eplain_part != nil
            text_part do
              content_type("text/plain; charset=# {type_plain}")
              #content_transfer_encoding("7bit")
              body "#{bodystr_plain}\nmailman@forma.culturadigital.cc para darte de baja escribe \"baja\" a info@culturadigital.cc"
            end
          end

          if eplain_part == nil && ehtml_part == nil
            body "#{bodystr}\nmailman@forma.culturadigital.cc para darte de baja escribe \"baja\" a info@culturadigital.cc" 
            charset=type
          end
          #puts e.attachments.inspect
          if e.attachments.length>0
            e.attachments.each do |a| 
              add_file a.encoded
            end
          end



        end
        puts "1 email sent"
      rescue => e
        puts "error: #{e}"
        $errorfile.write("#{Time.now}\nerror sending to #{tostr}: #{e},\nemail subject: #{subjectstr}\n\n")
        $errorfile.flush()
      end
    end
  end
end

$errorfile.close()
4

2 回答 2

2

这是未经测试的,并不是真正尝试查找或修复错误。它是为了展示你的代码应该是什么样子,用更惯用的 Ruby 代码编写。因此,它可能会解决您遇到的问题。如果没有,至少您会更好地了解应该如何编写代码:

require 'mail'
  • 为可重用的文字字符串定义一些常量。在顶部执行此操作,这样您就不必搜索代码来更改多个位置的内容,从而很可能会错过其中一个。

    PATH_TO_FILES = "C:/Users/j.de_miguel/Desktop/mailman.forma"
    BODY_BOILERPLATE_FORMAT = "%s\nmailman@forma.culturadigital.cc para darte de baja escribe \"baja\" a info@culturadigital.cc"
    
  • 将您的方法分组到文件顶部,在常量之后。

  • 我们打开使用'a',而不是'a+'。我们不需要读/写,我们只需要写。
  • 这将根据需要打开和关闭文件。
  • 关闭文件会自动刷新。
  • 如果您经常调用 log 方法,那么有更好的方法可以做到这一点,但这不是重量级脚本。
  • 我正在使用File.join基于路径构建文件名。File.join知道路径分隔符并自动执行正确的操作。
  • String.%使创建标准输出格式变得容易。

    def log(text)
    
      File.open(File.join(PATH_TO_FILES, "error_log2.txt"), 'a') do |log_file|
        log_file.puts "%s : %s" % [Time.now, text]
      end
    
    end
    
  • Ruby 中的方法名是snake_case,而不是CamelCase。

  • 没有理由进行多次gsub!测试,也没有必要进行条件测试。如果要清除的子字符串存在于字符串中,gsub则会执行此操作,否则继续。链接gsub方法将代码减少到一行。
  • gsub可能/应该可能sub,除非您知道字符串中可能有多个命中要替换。
  • return是多余的,所以我们不使用它,除非我们显式地返回一个值来过早地离开一个块。

    def delete_subject_recursion(subjstr)
    
      subjstr.gsub(/.\[FORMA 2013\]/,"").gsub(/((?i)Re: ){2,}/, "Re: ")
    
    end
    
  • 因为registered应该是一个布尔值,any?所以用来做测试。如果找到任何匹配项,则any?退出并返回true

    def user_is_registered(mailaddr)
    
      registered = subscribers.any?{ |s| mailaddr == s }
      log("user #{ mailaddr } attempted to mailman") unless registered
    
      registered
    
    end
    
  • 用于foreach遍历文件的行。

    subscribers = []
    File.foreach(File.join(PATH_TO_FILES, "subscribers2.txt")) do |line| 
      subscribers << line.chomp if line['@']
    end
    
    puts subscribers
    
    log('')
    
    Mail.defaults do
    
      retriever_method(
        :imap,
        {
          :address    => "imap.1and1.es",
          :port       => 143, 
          :user_name  => "mailman@somedomain.com",
          :password   => "xxxxxxxx",
          :enable_ssl => false 
        }
      )
    
      delivery_method(
        :smtp,
        {
          :address              => "smtp.1and1.es",
          :port                 => 587,
          :domain               => '1and1.es',
          :user_name            => 'mailman@somaedomain.com',
          :password             => 'xxxxxxxxxxxx',
          :authentication       => 'plain',
          :enable_starttls_auto => true  
        }
      )
    
    end
    
    #emailslist=Mail.find(keys: ['NOT','SEEN'])
    emailslist = [Mail.last]
    
    emailslist.each do |e|
    
  • 在这里使用三元语句可能是不可取的,但我离开了它。

  • 格式化成列使其更易于阅读。
  • 组织您的作业和使用,以免它们散布在整个文件中。

      eplain_part = e.text_part ? e.text_part.body.decoded : nil
      type_plain  = eplain_part ? e.text_part.charset.to_s : nil
      ehtml_part  = e.html_part ? e.html_part.body.decoded : nil
      type_html   = ehtml_part  ? e.html_part.charset.to_s : nil
    
      e_charset = e.charset
      body_str  = e_charset ? e.body.decoded.to_s.force_encoding(e_charset) : nil
      e_charset = e_charset ? e_charset.to_s : type_plain
      puts e_charset.inspect
    
      subjectstr = e.subject.to_s.encode(e_charset)
      fromstr    = e.from.first.to_s.encode(e_charset)
      puts fromstr
    
      bodystr_plain = eplain_part ? eplain_part.force_encoding(type_plain) : nil
      bodystr_html  = ehtml_part  ? ehtml_part.force_encoding(type_html)   : nil
    
      subscribers.each do |subscriber|
    
        puts subscriber.inspect
    
        if !subjectstr[/^\[FORMA 2013\]/] && user_is_registered(fromstr)
    
          subjectstr = delete_subject_recursion(subjectstr)
    
          begin
    
            Mail.deliver do
    
              from   fromstr
              to      "mailman@somedomain.com"
              bcc  subscriber
              subject "[FORMA 2013] #{ subjectstr }"
    
              if ehtml_part
                html_part do
                  content_type("text/html; charset=#{ type_html }")
                  #content_transfer_encoding("7bit")
                  body BODY_BOILERPLATE_FORMAT % bodystr_html
                end
              end
    
              if eplain_part
                text_part do
                  content_type("text/plain; charset=#{ type_plain }")
                  #content_transfer_encoding("7bit")
                  body BODY_BOILERPLATE_FORMAT % bodystr_plain
                end
              end
    
              if !eplain_part && !ehtml_part
                body BODY_BOILERPLATE_FORMAT % body_str
                charset = e_charset
              end
    
              #puts e.attachments.inspect
              e.attachments.each { |a| add_file a.encoded } if e.attachments.length > 0
            end
    
            puts "1 email sent"
    
          rescue => e
    
            puts "error: #{ e }"
            log("error sending to #{ subscriber }: #{ e },\nemail subject: #{ subjectstr }")
    
          end
        end
      end
    end
    

if e.attachments.length>0
  e.attachments.each do |a| 
    add_file a
  end
end

if可以使用尾随条件测试将其重构为简单的单行代码:

e.attachments.each { |a| add_file a.encoded } if e.attachments.length > 0

当你做一些简单的事情时,使用这样的单行是可以的。不要将它们用于更复杂的代码,因为您会产生视觉噪音,这会使您的代码难以理解和阅读。

但是让我们看看上面的代码实际上在做什么。e.attachments在这种情况下似乎正在返回一个数组或某种可枚举的集合,否则each将无法正常工作。length将告诉我们返回的“数组”(或任何它是什么)中有多少元素attachments

如果length为零,那么我们不想做任何事情,所以我们可以说:

e.attachments.each { |a| add_file a.encoded } unless e.attachments.empty?

(假设attachments实现了一个empty?方法。)

不过,这也有点多余。如果e.attachments已经是空的,该怎么each办?它会检查是否返回了一个包含任何元素的数组,如果它是空的,它将完全跳过它的块,就像触发attachments了尾随条件一样有效。if太棒了,我们可以改用这个:

e.attachments.each { |a| add_file a.encoded }

红宝石风格指南:

第二个是基于第一个。

于 2013-10-01T16:23:51.683 回答
0

Tin Mans 的回答大多有效。我更改了添加附件的方式,因为他的版本不适合我。

e.attachments.each { |a| attachments[a.filename] = a.decoded } if e.attachments.length > 0
于 2014-10-13T19:52:31.453 回答