2013-10-01 88 views
0

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

$emailslist.each do |e| 
    Mail.deliver do 
    from fromstr 
    to "[email protected]" 
    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 => "[email protected]", 
          :password => "xxxxxxxx", 
          :enable_ssl => false } 

    delivery_method :smtp, { :address    => "smtp.1and1.es", 
          :port     => 587, 
          :domain    => '1and1.es', 
          :user_name   => '[email protected]', 
          :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  "[email protected]" 
      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}\[email protected] para darte de baja escribe \"baja\" a [email protected]" 
      end 
      end 

      if eplain_part != nil 
      text_part do 
       content_type("text/plain; charset=# {type_plain}") 
       #content_transfer_encoding("7bit") 
       body "#{bodystr_plain}\[email protected] para darte de baja escribe \"baja\" a [email protected]" 
      end 
      end 

      if eplain_part == nil && ehtml_part == nil 
      body "#{bodystr}\[email protected] para darte de baja escribe \"baja\" a [email protected]" 
      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() 
+0

它没有工作的原因是因为'e'没有价值,它是'nil'。那么为什么'e'没有价值?你的$ emailslist是空的吗?或者,它是否包含“无”值?你没有向我们展示足以合理回答你的问题。 –

+0

'e'不是零,否则它不会通过if语句。没有附件,它确实工作正常。 – fartagaintuxedo

+0

如果我打印'e.attachments.inspect'它实际上显示附件。 – fartagaintuxedo

回答

2

这是未经测试的,并不是真的试图找到或修复该错误。这是为了显示您的代码应该是的外观,用更习惯的Ruby代码编写。因此,它可能会解决您所看到的问题。如果没有,至少你有更好的想法,你应该如何编写代码:

require 'mail' 
  • 定义一些常量中得到重用文字字符串。在顶部执行此操作,因此您无需搜索代码即可在多个位置更改事物,因此您可能会错过其中的一个。

    PATH_TO_FILES = "C:/Users/j.de_miguel/Desktop/mailman.forma" 
    BODY_BOILERPLATE_FORMAT = "%s\[email protected] para darte de baja escribe \"baja\" a [email protected]" 
    
  • 将常量之后的方法分组到文件顶部。

  • 我们打开使用'a',而不是'a+'。我们不需要读/写,我们只需要写。
  • 根据需要打开和关闭文件。
  • 自动关闭文件进行刷新。
  • 如果你经常调用日志方法,那么有更好的方法来做到这一点,但这不是一个重量级的脚本。
  • 我使用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 => "[email protected]", 
         :password => "xxxxxxxx", 
         :enable_ssl => false 
        } 
    ) 
    
        delivery_method(
        :smtp, 
        { 
         :address    => "smtp.1and1.es", 
         :port     => 587, 
         :domain    => '1and1.es', 
         :user_name   => '[email protected]', 
         :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  "[email protected]" 
          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一样。 SOOOooo,我们可以使用它代替:

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

红宝石风格指南:

第二个是基于第一。

+0

哇,谢谢你的红宝书课!真的,非常感谢 - id从来没有机会知道这种东西,否则,因为我总是编码独自+没有计算机科学背景:)/我会测试你的代码,看看它是如何去的。 – fartagaintuxedo

+1

没问题。每种语言都有其风格指南。我为Ruby添加了两个链接,一个基于另一个。多读几遍总是好的,然后在你学习的时候定期重读。指南就是这样,“指南”,而不是法律。根据可读性和可维护性使用最有意义的内容,因为这些内容有助于我们理解一年后写入的内容。我还添加了一些“添加附件”代码的重构。仍然不能保证代码的正常工作,因为我没有设置系统来测试它,但它又是更习惯Ruby。 –

0

Tin Mans的答案大多是作品。由于他的版本不适合我,我改变了附件的添加方式。

e.attachments.each { |a| attachments[a.filename] = a.decoded } if e.attachments.length > 0