## Notion document https://www.notion.so/chatwoot/Email-IMAP-Issue-30aa5f274c928062aa6bddc2e5877a63?showMoveTo=true&saveParent=true ## Description PLAIN IMAP channels (non-OAuth) were silently retrying failed authentication every minute, forever. When credentials are wrong/expired, Net::IMAP::NoResponseError was caught and logged but channel.authorization_error! was never called — so the Redis error counter never incremented, reauthorization_required? was never set, and admins were never notified. OAuth channels already had this handled correctly via the Reauthorizable concern. Additionally, Net::IMAP::ResponseParseError (raised by non-RFC-compliant IMAP servers) was falling through to the StandardError catch-all, flooding Estimated impact before fix: ~70–75 broken IMAP inboxes generating ~700k–750k wasted Sidekiq jobs/week. ## Type of change - [ ] Bug fix (non-breaking change which fixes an issue) ## Checklist: - [ ] My code follows the style guidelines of this project - [ ] I have performed a self-review of my code - [ ] I have commented on my code, particularly in hard-to-understand areas - [ ] I have made corresponding changes to the documentation - [ ] My changes generate no new warnings - [ ] I have added tests that prove my fix is effective or that my feature works - [ ] New and existing unit tests pass locally with my changes - [ ] Any dependent changes have been merged and published in downstream modules
85 lines
2.9 KiB
Ruby
85 lines
2.9 KiB
Ruby
# == Schema Information
|
|
#
|
|
# Table name: channel_email
|
|
#
|
|
# id :bigint not null, primary key
|
|
# email :string not null
|
|
# forward_to_email :string not null
|
|
# imap_address :string default("")
|
|
# imap_enable_ssl :boolean default(TRUE)
|
|
# imap_enabled :boolean default(FALSE)
|
|
# imap_login :string default("")
|
|
# imap_password :string default("")
|
|
# imap_port :integer default(0)
|
|
# provider :string
|
|
# provider_config :jsonb
|
|
# smtp_address :string default("")
|
|
# smtp_authentication :string default("login")
|
|
# smtp_domain :string default("")
|
|
# smtp_enable_ssl_tls :boolean default(FALSE)
|
|
# smtp_enable_starttls_auto :boolean default(TRUE)
|
|
# smtp_enabled :boolean default(FALSE)
|
|
# smtp_login :string default("")
|
|
# smtp_openssl_verify_mode :string default("none")
|
|
# smtp_password :string default("")
|
|
# smtp_port :integer default(0)
|
|
# verified_for_sending :boolean default(FALSE), not null
|
|
# created_at :datetime not null
|
|
# updated_at :datetime not null
|
|
# account_id :integer not null
|
|
#
|
|
# Indexes
|
|
#
|
|
# index_channel_email_on_email (email) UNIQUE
|
|
# index_channel_email_on_forward_to_email (forward_to_email) UNIQUE
|
|
#
|
|
|
|
class Channel::Email < ApplicationRecord
|
|
include Channelable
|
|
include Reauthorizable
|
|
|
|
AUTHORIZATION_ERROR_THRESHOLD = 10
|
|
|
|
# TODO: Remove guard once encryption keys become mandatory (target 3-4 releases out).
|
|
if Chatwoot.encryption_configured?
|
|
encrypts :imap_password
|
|
encrypts :smtp_password
|
|
end
|
|
|
|
self.table_name = 'channel_email'
|
|
EDITABLE_ATTRS = [:email, :imap_enabled, :imap_login, :imap_password, :imap_address, :imap_port, :imap_enable_ssl,
|
|
:smtp_enabled, :smtp_login, :smtp_password, :smtp_address, :smtp_port, :smtp_domain, :smtp_enable_starttls_auto,
|
|
:smtp_enable_ssl_tls, :smtp_openssl_verify_mode, :smtp_authentication, :provider, :verified_for_sending].freeze
|
|
|
|
validates :email, uniqueness: true
|
|
validates :forward_to_email, uniqueness: true
|
|
|
|
before_validation :ensure_forward_to_email, on: :create
|
|
|
|
def name
|
|
'Email'
|
|
end
|
|
|
|
def microsoft?
|
|
provider == 'microsoft'
|
|
end
|
|
|
|
def google?
|
|
provider == 'google'
|
|
end
|
|
|
|
def legacy_google?
|
|
imap_enabled && imap_address == 'imap.gmail.com'
|
|
end
|
|
|
|
def backoff_log_identifier
|
|
"Error for email channel - #{inbox.id}"
|
|
end
|
|
|
|
private
|
|
|
|
def ensure_forward_to_email
|
|
self.forward_to_email ||= "#{SecureRandom.hex}@#{account.inbound_email_domain}"
|
|
end
|
|
end
|