我已将 mailman gem 集成到我的 rails 项目中。它成功地从 gmail 获取电子邮件。在我的应用程序中,我的电子邮件有一个模型消息。电子邮件已正确保存为消息模型。
问题是电子邮件有时会被保存多次,我无法识别模式。有些电子邮件保存一次,有些保存两次,有些保存三次。
但是我在我的代码中找不到失败。
这是我的 mailman_server 脚本:
脚本/mailman_server
#!/usr/bin/env ruby
# encoding: UTF-8
require "rubygems"
require "bundler/setup"
require File.expand_path(File.join(File.dirname(__FILE__), '..', 'config', 'environment'))
require 'mailman'
Mailman.config.ignore_stdin = true
#Mailman.config.logger = Logger.new File.expand_path("../../log/mailman_#{Rails.env}.log", __FILE__)
if Rails.env == 'test'
Mailman.config.maildir = File.expand_path("../../tmp/test_maildir", __FILE__)
else
Mailman.config.logger = Logger.new File.expand_path("../../log/mailman_#{Rails.env}.log", __FILE__)
Mailman.config.poll_interval = 15
Mailman.config.imap = {
server: 'imap.gmail.com',
port: 993, # usually 995, 993 for gmail
ssl: true,
username: 'my@email.com',
password: 'my_password'
}
end
Mailman::Application.run do
default do
begin
Message.receive_message(message)
rescue Exception => e
Mailman.logger.error "Exception occurred while receiving message:\n#{message}"
Mailman.logger.error [e, *e.backtrace].join("\n")
end
end
end
电子邮件在我的 Message 类中处理:
def self.receive_message(message)
if message.from.first == "my@email.com"
Message.save_bcc_mail(message)
else
Message.save_incoming_mail(message)
end
end
def self.save_incoming_mail(message)
part_to_use = message.html_part || message.text_part || message
if Kontakt.where(:email => message.from.first).empty?
encoding = part_to_use.content_type_parameters['charset']
Message.create topic: message.subject, message: part_to_use.body.decoded.force_encoding(encoding).encode('UTF-8'), communication_partner: message.from.first, inbound: true, time: message.date
else
encoding = part_to_use.content_type_parameters['charset']
Message.create topic: message.subject, message: part_to_use.body.decoded.force_encoding(encoding).encode('UTF-8'), communication_partner: message.from.first, inbound: true, time: message.date, messageable_type: 'Company', messageable_id: Kontakt.where(:email => message.from.first).first.year.id
end
end
def self.save_bcc_mail(message)
part_to_use = message.html_part || message.text_part || message
if Kontakt.where(:email => message.to.first).empty?
encoding = part_to_use.content_type_parameters['charset']
Message.create topic: message.subject, message: part_to_use.body.decoded.force_encoding(encoding).encode('UTF-8'), communication_partner: message.to.first, inbound: false, time: message.date
else
encoding = part_to_use.content_type_parameters['charset']
Message.create topic: message.subject, message: part_to_use.body.decoded.force_encoding(encoding).encode('UTF-8'), communication_partner: message.to.first, inbound: false, time: message.date, messageable_type: 'Company', messageable_id: Kontakt.where(:email => message.to.first).first.year.id
end
end
我已经用这个脚本守护了 mailman_server:
脚本/mailman_daemon
#!/usr/bin/env ruby
require 'rubygems'
require "bundler/setup"
require 'daemons'
Daemons.run('script/mailman_server')
我用 capistrano 部署。
这是负责停止、启动和重新启动我的 mailman_server 的部分:
脚本/部署.rb
set :rails_env, "production" #added for delayed job
after "deploy:stop", "delayed_job:stop"
after "deploy:start", "delayed_job:start"
after "deploy:restart", "delayed_job:restart"
after "deploy:stop", "mailman:stop"
after "deploy:start", "mailman:start"
after "deploy:restart", "mailman:restart"
namespace :deploy do
desc "mailman script ausfuehrbar machen"
task :mailman_executable, :roles => :app do
run "chmod +x #{current_path}/script/mailman_server"
end
desc "mailman daemon ausfuehrbar machen"
task :mailman_daemon_executable, :roles => :app do
run "chmod +x #{current_path}/script/mailman_daemon"
end
end
namespace :mailman do
desc "Mailman::Start"
task :start, :roles => [:app] do
run "cd #{current_path};RAILS_ENV=#{fetch(:rails_env)} bundle exec script/mailman_daemon start"
end
desc "Mailman::Stop"
task :stop, :roles => [:app] do
run "cd #{current_path};RAILS_ENV=#{fetch(:rails_env)} bundle exec script/mailman_daemon stop"
end
desc "Mailman::Restart"
task :restart, :roles => [:app] do
mailman.stop
mailman.start
end
end
是不是在我的部署过程中几乎同时启动了多个 mailman 服务器实例,然后每个实例几乎同时轮询?第一个实例之前的第二个和第三个实例池将电子邮件标记为已读并轮询和处理电子邮件吗?
更新 30.01。
我已将轮询间隔设置为 60 秒。但这没有任何改变。
我检查了存储 mailman pid 文件的文件夹。只有一个邮递员 pid 文件。所以肯定只有一个 mailman 服务器在运行。我检查了日志文件,可以看到消息被多次获取:
Mailman v0.7.0 started
IMAP receiver enabled (my@email.com).
Polling enabled. Checking every 60 seconds.
Got new message from 'my.other@email.com' with subject 'Test nr 0'.
Got new message from 'my.other@email.com' with subject 'Test nr 1'.
Got new message from 'my.other@email.com' with subject 'test nr 2'.
Got new message from 'my.other@email.com' with subject 'test nr 2'.
Got new message from 'my.other@email.com' with subject 'test nr 3'.
Got new message from 'my.other@email.com' with subject 'test nr 4'.
Got new message from 'my.other@email.com' with subject 'test nr 4'.
Got new message from 'my.other@email.com' with subject 'test nr 4'.
所以在我看来,问题肯定出在我的邮递员服务器代码中。
更新 31.1。
在我看来,这与我的生产机器有关。当我在开发中使用完全相同的配置进行测试时(今天早上将我的本地数据库从 sqlite 更改为 mysql 进行测试),因为在生产机器上我没有得到重复。我的代码可能一切正常,但生产机器有问题。会问我的主人他们是否能找到解决方案。为了解决这个问题,我将采用 Ariejan 的建议。
解决方案: 我发现了问题。我部署到一台机器,其中 tmp 目录是所有版本之间共享的目录。我忘了定义应该保存 mailman_daemon 的 pid 文件的路径。所以它被保存在脚本目录而不是 /tmp/pids 目录中。因此,旧的 mailman_daemon 在新部署后无法停止。这导致了一大群工作的 mailman_daemons 正在轮询我的邮件帐户......在杀死所有这些进程之后一切顺利!不再重复!