新手问题 [已解决] Talk about decode email in redmine again

small_fish__ · 2012年12月08日 · 最后由 lgn21st 回复于 2012年12月10日 · 5318 次阅读

不好意思,我又来求助大家了!希望大家在思路上或方法上给点灵感。

案例需求:

在日常产品运营和开发过程中,很多同事发现了一些 bug,但苦于不知道 bug 该怎么提,或该向谁提,导致了产品 bug 不能快速得到反馈,那么也就无法及时得到处理。

公司现在用的是 Redmine(Rails2.3.14)作为项目管理的,公司就希望在 redmine 中添加一个bug email to a new issue的功能。

what is 'bug mail to a new issue'?

意思就是公司员工在发现了 bug 的时候,可以及时的向一特定的邮箱([email protected]),发送一封邮件,那么此 Redmine 功能能够根据此邮件的内容生成一个对应的 bug 工单。

what are principles of a mail to a Issue?

1.此功能只对公司邮箱有效(非公司邮箱向[email protected]发送的邮件将被忽略)

  1. - 邮件 subject=Issue.subject;邮件 body =Issue.description(但是为了知道是谁提的 bug,需要在 description 的开始,加上发送人的邮件地址和发送的时间);邮件发送人 = Issue.author(但是如果此用户不是 redmine 用户,那么其 author 是指定用户) 3.bug 邮箱的邮件不可删除。 4.邮件内容没有限制。 5.可以简化的操作(邮件的内容在 redmine 中其样式可以不一样,图片等资源可以放在一起。)

why I don't use redmine's function for this?

redmine 自带了此功能,但是发现它对 mail 的内容和格式有特殊要求,不太符合公司要求,所以我觉得不采用其自带的(是否有重新发明轮子的感觉)

what I have done for this?

我的想法很单纯,写一个 rake,然后再写个 crontab 定时去执行这个 rake。 那么我的 rake 要做什么? 1.取邮件,即获取最新的邮件,而且要排除已处理过的邮件。我的做法是每 5 分钟取最新的 5 条邮件(按照公司邮件提交的频率),然后拿到上一次处理过的最后一条邮件,如果此 5 条中没有此记录,判断得出 5 条都是新的,如果有,那么 就从这条邮件中的下一条开始算起,每次操作完成后都缓存下组后一条的邮件记录,并过滤掉不是本公司的邮件,具体代码形如:

# get new and xxx.com emails
emails = Mail.find(:what => :last, :count => 5, :order => :asc)
message_ids = emails.map{|mail| mail.message_id}
message_id = IO.readlines("#{RAILS_ROOT}/doc/mail_box").last
message_id = message_id.strip if message_id
index = message_ids.index(message_id)
emails = emails[index+1,emails.size] if index
emails = emails.select{|mail| mail if(mail.from.first.to_s=~/xxx.com$/) }

2.邮件到 Issue 的转换,主要用到了 mail 这个 Gem 包,并在转换的过程中记录日志,以便日后查看,具体代码如下:

#to new bug issue
 unless emails.blank?
   out_put_file = File.open("#{RAILS_ROOT}/doc/mail_box","a")
   log_file_path = "#{RAILS_ROOT}/log/mail.log"
   log_file = nil
   if File.exist? log_file_path
      log_file = File.open(log_file_path,"a") 
   else
      log_file = File.new(log_file_path,"w+") 
   end
   emails.each do |mail|
      issue = Issue.new 
      issue.tracker_id = 1
      issue.subject = (mail.subject + "#由Bug邮箱自动生成")
      author = User.find_by_mail(mail.from.first)
      author = User.find_by_mail(DEFAULT_EMAIL) unless author
      issue.author_id = author.id
      issue.description = (get_mail_body mail)
      issue.project_id = DEFAULT_TEAM
      issue.save!
      out_put_file.puts mail.message_id
      out_put_file.flush
      log_file.puts (mail.date.strftime("%F %R:%S") + mail.subject)
      log_file.flush
   end

   #record new mail message_id
   out_put_file.close
   log_file.close
 end

其中所依赖一个解析邮件 body 的方法

#get email body
 def get_mail_body(mail)
    mail.parts.each do |part|
      next unless part.content_type =~ /^text\/html/
      content = part.decode_body
      charset = mail.parts.last.charset.to_s
      unless  charset == "utf-8"
         content = Iconv.iconv("utf-8", charset, content) 
      end
      return content
    end
 end

what my code can do and can't do?

对于文本格式或普通 html 格式(及没有图片等内容)邮件处理比较成功,但是有图片等资源此代码解析就会失效。

what is my problems?

1.现在我解析 email body 得到的是 html 代码,然后在在 redmine 中直接以 html 显示,而 redmine 中这段用的是 ,所以我还需要从 html 转化成它的格式,(不知道有没有现成的方法或 gem 包呢)。 2.关于邮件中图片的资源的获取,因为提 bug 的人很多不知道怎么描述,直接贴张图就 ok 了,故对图片的获取很重要。在此请教大家邮件中获取图片的方法?

what your idea.& solution?

happy to wait for you!

就应该用 redmine 自带那功能改改,你这样搞完全是乱来

个人觉得这个是一个很实用的小功能,完全可以写一个简单的小项目,或者集成到现有的内部系统中,从网站上提交。为什么要借助邮件绕一个弯来做呢?

而且,redmine 也为 ruby 提供了很好的 restful 借口。完全不必要模拟网站提交。http://www.redmine.org/projects/redmine/wiki/Rest_api_with_ruby

what is my problems?

这个部分我其实没有看懂,能不能具体给个例子,比如你得邮件格式,以及你想要得到得格式。

#4 楼 @lgn21st 例如有如下邮件:

我在 redmine 中生成的 issue 的 descrption 的格式大致应该为: 作者:[email protected], 时间:email_time 具体内容: 作者:bug 反馈,状态:New,优先级:Normal,优先级:Normal。。。。。。 Bug 如图示一:

#5 楼 @small_fish__ 我明白你的意思了,你是要把 Email 中的格式转换成 Redmine 中等同显示的格式,我不使用 Redmine,没有办法直接给你代码,但是我认为是写一个 adapter 来解决问题。

我想我会这么做:在 Redmine 中建立一个目标格式的例子,然后到数据库中找出 Redmine 保存的这个例子的 raw string,然后写一个用于规则转换方法,把 Email 的格式转换成 Redmine 的格式,这里可能需要很多正则的技巧。

需要 登录 后方可回复, 如果你还没有账号请 注册新账号