我想在不下载附件然后重新附加到新电子邮件的情况下执行此操作 这就是我的尝试:
$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()
答案 0 :(得分: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+'
打开。我们不需要读/写,我们只需要写。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
条件一样。 SOOOooo,我们可以改用它:
e.attachments.each { |a| add_file a.encoded }
Ruby Style指南:
第二个基于第一个。
答案 1 :(得分:0)
Tin Mans的回答大多有效。我更改了附件的添加方式,因为他的版本不适合我。
e.attachments.each { |a| attachments[a.filename] = a.decoded } if e.attachments.length > 0