ActionMailbox в рельсах изначально был заточен на использование платных 3rd-party сервисов. Подключить его к обычному имейлу можно было либо поднимая/перенастраивая почтовый сервер, либо через костыли. Костыли так или иначе заключались в поднятии дополнительного сервиса. Статья на Medium предлагает поднять fetchmail, заброшенный гем предлагает запускать почтовый клиент на Rust.
Ниже предлагаю решение, работающее на ActiveJob. Промежуток поллинга сообщений конфигурируется с помощью встроенных recurring jobs. Креденшиалы для почты хранятся во встроенных Rails Credentials. Решение не требует дополнительных сервисов, если вы уже используете SolidQueue или любой другой бэк, поддерживающий рекуррентные задачи. Из коробки деплоится Kamal.
Получаем и сохраняем все непрочитанные сообщения в ящике:
# app/jobs/action_mailbox/fetch_unread_emails_job.rb # frozen_string_literal: true require 'net/imap' class ActionMailbox::FetchUnreadEmailsJob < ApplicationJob queue_as :default def perform each_imap_message_id do |msg_id, imap| raw_source = imap.fetch(msg_id, 'RFC822')[0].attr['RFC822'] ActionMailbox::InboundEmail.create_and_extract_message_id!(raw_source) imap.store(msg_id, '+FLAGS', [:Seen]) end end private def each_imap_message_id imap = Net::IMAP.new(Rails.application.credentials.dig(:mail_ingress, :host), Rails.application.credentials.dig(:mail_ingress, :port).to_i, true) imap.login(Rails.application.credentials.dig(:mail_ingress, :username), Rails.application.credentials.dig(:mail_ingress, :password)) imap.select('INBOX') imap.search(['UNSEEN']).each do |msg_id| yield msg_id, imap end imap.logout imap.disconnect end end
Чистим все прочитанные письма старше месяца:
# app/jobs/action_mailbox/cleanup_old_emails_job.rb # frozen_string_literal: true require 'net/imap' class ActionMailbox::CleanupOldEmailsJob < ApplicationJob queue_as :default PERIOD = 1.month def perform imap = Net::IMAP.new(Rails.application.credentials.dig(:mail_ingress, :host), Rails.application.credentials.dig(:mail_ingress, :port).to_i, true) imap.login(Rails.application.credentials.dig(:mail_ingress, :username), Rails.application.credentials.dig(:mail_ingress, :password)) imap.select('INBOX') imap.search(['SEEN', 'BEFORE', PERIOD.ago.strftime('%d-%b-%Y')]).each do |msg_id| imap.store(msg_id, '+FLAGS', [:Deleted]) end imap.expunge imap.logout imap.disconnect end end
Конфиг для ActiveJob:
# config/recurring.yml production: fetch_unread_emails: class: ActionMailbox::FetchUnreadEmailsJob queue: background schedule: every 3 minutes cleanup_old_emails: class: ActionMailbox::CleanupOldEmailsJob queue: background schedule: daily at 2:30 am
Так выглядят креденшиалы для `bin/rails credentials:edit`:
mail_ingress: host: 'mail.example.com' port: 995 username: 'superbot@example.com password: 'h4ckerm4n'
Для англоязычной аудитории можно скидывать ссылку на gist:
https://gist.github.com/sandrew/c94bccb987d7862f09166f9b114b0995
