Improved email loop protection. Remember permanent delivery failed on user to prevent email loops.
This commit is contained in:
parent
2fe0b19a3d
commit
48e3da57ee
9 changed files with 841 additions and 42 deletions
|
@ -0,0 +1,73 @@
|
|||
# Copyright (C) 2012-2016 Zammad Foundation, http://zammad-foundation.org/
|
||||
|
||||
module Channel::Filter::BounceDeliveryPermanentFailed
|
||||
|
||||
def self.run(_channel, mail)
|
||||
|
||||
return if !mail[:mail_instance]
|
||||
return if !mail[:mail_instance].bounced?
|
||||
return if !mail[:attachments]
|
||||
|
||||
# remember, do not send notifications to certain recipients again if failed permanent
|
||||
mail[:attachments].each { |attachment|
|
||||
next if !attachment[:preferences]
|
||||
next if attachment[:preferences]['Mime-Type'] != 'message/rfc822'
|
||||
next if !attachment[:data]
|
||||
|
||||
result = Channel::EmailParser.new.parse(attachment[:data])
|
||||
next if !result[:message_id]
|
||||
message_id_md5 = Digest::MD5.hexdigest(result[:message_id])
|
||||
article = Ticket::Article.where(message_id_md5: message_id_md5).order('created_at DESC, id DESC').limit(1).first
|
||||
next if !article
|
||||
|
||||
# check user preferences
|
||||
next if mail[:mail_instance].action != 'failed'
|
||||
next if mail[:mail_instance].retryable? != false
|
||||
next if mail[:mail_instance].error_status != '5.1.1'
|
||||
|
||||
# get recipient of origin article, if only one - mark this user to not sent notifications anymore
|
||||
recipients = []
|
||||
if article.sender.name == 'System' || article.sender.name == 'Agent'
|
||||
%w(to cc).each { |line|
|
||||
next if article[line].blank?
|
||||
recipients = []
|
||||
begin
|
||||
list = Mail::AddressList.new(article[line])
|
||||
list.addresses.each { |address|
|
||||
next if address.address.blank?
|
||||
recipients.push address.address.downcase
|
||||
}
|
||||
rescue
|
||||
Rails.logger.info "Unable to parse email address in '#{article[line]}'"
|
||||
end
|
||||
}
|
||||
if recipients.count > 1
|
||||
recipients = []
|
||||
end
|
||||
end
|
||||
|
||||
# get recipient bounce mail, mark this user to not sent notifications anymore
|
||||
final_recipient = mail[:mail_instance].final_recipient
|
||||
if final_recipient.present?
|
||||
final_recipient.sub!(/rfc822;\s{0,10}/, '')
|
||||
if final_recipient.present?
|
||||
recipients.push final_recipient.downcase
|
||||
end
|
||||
end
|
||||
|
||||
# set user preferences
|
||||
recipients.each { |recipient|
|
||||
users = User.where(email: recipient)
|
||||
users.each { |user|
|
||||
next if !user
|
||||
user.preferences[:mail_delivery_failed] = true
|
||||
user.preferences[:mail_delivery_failed_data] = Time.zone.now
|
||||
user.save!
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
true
|
||||
|
||||
end
|
||||
end
|
|
@ -1,6 +1,6 @@
|
|||
# Copyright (C) 2012-2016 Zammad Foundation, http://zammad-foundation.org/
|
||||
|
||||
module Channel::Filter::BounceCheck
|
||||
module Channel::Filter::BounceFollowUpCheck
|
||||
|
||||
def self.run(_channel, mail)
|
||||
|
||||
|
@ -13,13 +13,17 @@ module Channel::Filter::BounceCheck
|
|||
next if !attachment[:preferences]
|
||||
next if attachment[:preferences]['Mime-Type'] != 'message/rfc822'
|
||||
next if !attachment[:data]
|
||||
|
||||
result = Channel::EmailParser.new.parse(attachment[:data])
|
||||
next if !result[:message_id]
|
||||
message_id_md5 = Digest::MD5.hexdigest(result[:message_id])
|
||||
article = Ticket::Article.where(message_id_md5: message_id_md5).order('created_at DESC, id DESC').limit(1).first
|
||||
next if !article
|
||||
|
||||
Rails.logger.debug "Follow up for '##{article.ticket.number}' in bounce email."
|
||||
mail[ 'x-zammad-ticket-id'.to_sym ] = article.ticket_id
|
||||
mail[ 'x-zammad-is-auto-response'.to_sym ] = true
|
||||
|
||||
return true
|
||||
}
|
||||
|
|
@ -813,6 +813,19 @@ perform changes on ticket
|
|||
recipients_checked = []
|
||||
recipients_raw.each { |recipient_email|
|
||||
|
||||
skip_user = false
|
||||
users = User.where(email: recipient_email)
|
||||
users.each { |user|
|
||||
next if user.preferences[:mail_delivery_failed] != true
|
||||
next if !user.preferences[:mail_delivery_failed_data]
|
||||
till_blocked = ((user.preferences[:mail_delivery_failed_data] - Time.zone.now - 60.days) / 60 / 60 / 24).round
|
||||
next if till_blocked.positive?
|
||||
logger.info "Send no trigger based notification to #{recipient_email} because email is marked as mail_delivery_failed for #{till_blocked} days"
|
||||
skip_user = true
|
||||
break
|
||||
}
|
||||
next if skip_user
|
||||
|
||||
# send notifications only to email adresses
|
||||
next if !recipient_email
|
||||
next if recipient_email !~ /@/
|
||||
|
|
|
@ -0,0 +1,35 @@
|
|||
class SettingDeliveryPermanentFailed < ActiveRecord::Migration
|
||||
def up
|
||||
|
||||
# return if it's a new setup
|
||||
return if !Setting.find_by(name: 'system_init_done')
|
||||
|
||||
setting = Setting.find_by(name: '0900_postmaster_filter_bounce_check')
|
||||
if setting
|
||||
setting.name = '0900_postmaster_filter_bounce_follow_up_check'
|
||||
setting.state = 'Channel::Filter::BounceFollowUpCheck'
|
||||
setting.save!
|
||||
else
|
||||
Setting.create_if_not_exists(
|
||||
title: 'Defines postmaster filter.',
|
||||
name: '0900_postmaster_filter_bounce_follow_up_check',
|
||||
area: 'Postmaster::PreFilter',
|
||||
description: 'Defines postmaster filter to identify postmaster bounced - to handle it as follow-up of the original ticket.',
|
||||
options: {},
|
||||
state: 'Channel::Filter::BounceFollowUpCheck',
|
||||
frontend: false
|
||||
)
|
||||
end
|
||||
Setting.create_if_not_exists(
|
||||
title: 'Defines postmaster filter.',
|
||||
name: '0950_postmaster_filter_bounce_delivery_permanent_failed',
|
||||
area: 'Postmaster::PreFilter',
|
||||
description: 'Defines postmaster filter to identify postmaster bounced - disable sending notification on permanent deleivery failed.',
|
||||
options: {},
|
||||
state: 'Channel::Filter::BounceDeliveryPermanentFailed',
|
||||
frontend: false
|
||||
)
|
||||
|
||||
end
|
||||
|
||||
end
|
|
@ -2327,11 +2327,20 @@ Setting.create_if_not_exists(
|
|||
)
|
||||
Setting.create_if_not_exists(
|
||||
title: 'Defines postmaster filter.',
|
||||
name: '0900_postmaster_filter_bounce_check',
|
||||
name: '0900_postmaster_filter_bounce_follow_up_check',
|
||||
area: 'Postmaster::PreFilter',
|
||||
description: 'Defines postmaster filter to identify postmaster bounced - to handle it as follow-up of the original ticket.',
|
||||
options: {},
|
||||
state: 'Channel::Filter::BounceCheck',
|
||||
state: 'Channel::Filter::BounceFollowUpCheck',
|
||||
frontend: false
|
||||
)
|
||||
Setting.create_if_not_exists(
|
||||
title: 'Defines postmaster filter.',
|
||||
name: '0950_postmaster_filter_bounce_delivery_permanent_failed',
|
||||
area: 'Postmaster::PreFilter',
|
||||
description: 'Defines postmaster filter to identify postmaster bounced - disable sending notification on permanent deleivery failed.',
|
||||
options: {},
|
||||
state: 'Channel::Filter::BounceDeliveryPermanentFailed',
|
||||
frontend: false
|
||||
)
|
||||
Setting.create_if_not_exists(
|
||||
|
|
230
test/fixtures/mail55.box
vendored
Normal file
230
test/fixtures/mail55.box
vendored
Normal file
|
@ -0,0 +1,230 @@
|
|||
Return-Path: <MAILER-DAEMON>
|
||||
Delivered-To: example@zammad.com
|
||||
Received: by mx1.zammad.loc (Postfix)
|
||||
id 738F920A13B2; Fri, 26 May 2017 17:01:45 +0200 (CEST)
|
||||
Date: Fri, 26 May 2017 17:01:45 +0200 (CEST)
|
||||
From: MAILER-DAEMON@mx1.zammad.loc (Mail Delivery System)
|
||||
Subject: Undelivered Mail Returned to Sender
|
||||
To: example@zammad.com
|
||||
Auto-Submitted: auto-replied
|
||||
MIME-Version: 1.0
|
||||
Content-Type: multipart/report; report-type=delivery-status;
|
||||
boundary="207FF20398ED.1495810905/mx1.zammad.loc"
|
||||
Message-Id: <20170526150145.738F920A13B2@mx1.zammad.loc>
|
||||
|
||||
This is a MIME-encapsulated message.
|
||||
|
||||
--207FF20398ED.1495810905/mx1.zammad.loc
|
||||
Content-Description: Notification
|
||||
Content-Type: text/plain; charset=us-ascii
|
||||
|
||||
This is the mail system at host mx1.zammad.loc.
|
||||
|
||||
I'm sorry to have to inform you that your message could not
|
||||
be delivered to one or more recipients. It's attached below.
|
||||
|
||||
For further assistance, please send mail to postmaster.
|
||||
|
||||
If you do so, please include this problem report. You can
|
||||
delete your own text from the attached returned message.
|
||||
|
||||
The mail system
|
||||
|
||||
<ticket-bounce-trigger2@example.com>: host aspmx.l.example.com[108.177.96.26] said:
|
||||
550-5.1.1 The email account that you tried to reach does not exist. Please
|
||||
try 550-5.1.1 double-checking the recipient's email address for typos or
|
||||
550-5.1.1 unnecessary spaces. Learn more at 550 5.1.1
|
||||
https://support.example.com/mail/?p=NoSuchUser l59si1635011edl.281 - gsmtp
|
||||
(in reply to RCPT TO command)
|
||||
|
||||
--207FF20398ED.1495810905/mx1.zammad.loc
|
||||
Content-Description: Delivery report
|
||||
Content-Type: message/delivery-status
|
||||
|
||||
Reporting-MTA: dns; mx1.zammad.loc
|
||||
X-Postfix-Queue-ID: 207FF20398ED
|
||||
X-Postfix-Sender: rfc822; example@zammad.com
|
||||
Arrival-Date: Fri, 26 May 2017 17:01:45 +0200 (CEST)
|
||||
|
||||
Final-Recipient: rfc822; ticket-bounce-trigger2@example.com
|
||||
Original-Recipient: rfc822;ticket-bounce-trigger2@example.com
|
||||
Action: failed
|
||||
Status: 5.1.1
|
||||
Remote-MTA: dns; aspmx.l.example.com
|
||||
Diagnostic-Code: smtp; 550-5.1.1 The email account that you tried to reach does
|
||||
not exist. Please try 550-5.1.1 double-checking the recipient's email
|
||||
address for typos or 550-5.1.1 unnecessary spaces. Learn more at 550 5.1.1
|
||||
https://support.example.com/mail/?p=NoSuchUser l59si1635011edl.281 - gsmtp
|
||||
|
||||
--207FF20398ED.1495810905/mx1.zammad.loc
|
||||
Content-Description: Undelivered Message
|
||||
Content-Type: message/rfc822
|
||||
|
||||
Return-Path: <example@zammad.com>
|
||||
Received: from apn0000.dc.zammad.com (apn0000.dc.zammad.com [88.0.0.0])
|
||||
by mx1.zammad.loc (Postfix) with ESMTP id 207FF20398ED
|
||||
for <ticket-bounce-trigger2@example.com>; Fri, 26 May 2017 17:01:45 +0200 (CEST)
|
||||
Received: by apn0000.dc.zammad.com (Postfix, from userid 1050)
|
||||
id 08443420973; Fri, 26 May 2017 17:01:45 +0200 (CEST)
|
||||
Date: Fri, 26 May 2017 17:01:45 +0200
|
||||
From: Twelve SaaS GmbH Helpdesk <example@zammad.com>
|
||||
To: ticket-bounce-trigger2@example.com
|
||||
Message-ID: <20170526150141.232.13312@example.zammad.loc>
|
||||
In-Reply-To:
|
||||
References: <20170526150142.232.819805@example.zammad.loc>
|
||||
<20170526150119.6C5E520A13B2@mx1.zammad.loc>
|
||||
<20170526150141.232.799457@example.zammad.loc>
|
||||
<20170526150117.0560820A13B3@mx1.zammad.loc>
|
||||
<20170526150115.232.175460@example.zammad.loc>
|
||||
<20170526150108.232.482766@example.zammad.loc>
|
||||
<20170526150041.F3D2C20A13B3@mx1.zammad.loc>
|
||||
<20170526150036.232.513248@example.zammad.loc>
|
||||
<20170526150008.6AE8A20A13B8@mx1.zammad.loc>
|
||||
<20170526150004.232.103372@example.zammad.loc>
|
||||
<20170526145940.D799220A13B3@mx1.zammad.loc>
|
||||
<20170526145932.232.91897@example.zammad.loc>
|
||||
<20170526145906.8FCA520A13B2@mx1.zammad.loc>
|
||||
<20170526145901.232.269971@example.zammad.loc>
|
||||
<lyHYjBDWwaU5KGbDrCyOfA@notifications.example.com>
|
||||
Subject: =?UTF-8?Q?[Ticket#1705265400361]_RE:_Thanks_for_your_follow_up?=
|
||||
=?UTF-8?Q?_=28G_Suite:_Benachrichtigung_=C3=BCber_Verl=C3=A4ngerung_in_30?=
|
||||
=?UTF-8?Q?_Tagen=29?=
|
||||
Mime-Version: 1.0
|
||||
Content-Type: multipart/mixed;
|
||||
boundary="--==_mimepart_5928435950b1_22d42086504355bc";
|
||||
charset=UTF-8
|
||||
Content-Transfer-Encoding: 7bit
|
||||
Organization: Twelve SaaS GmbH
|
||||
X-Loop: yes
|
||||
Precedence: bulk
|
||||
Auto-Submitted: auto-generated
|
||||
X-Auto-Response-Suppress: All
|
||||
X-Powered-By: Zammad - Helpdesk/Support (https://zammad.org/)
|
||||
X-Mailer: Zammad Mail Service
|
||||
|
||||
|
||||
----==_mimepart_5928435950b1_22d42086504355bc
|
||||
Content-Type: multipart/alternative;
|
||||
boundary="--==_mimepart_592843594d35_22d4208650435394";
|
||||
charset=UTF-8
|
||||
Content-Transfer-Encoding: 7bit
|
||||
|
||||
|
||||
----==_mimepart_592843594d35_22d4208650435394
|
||||
Content-Type: text/plain;
|
||||
charset=UTF-8
|
||||
Content-Transfer-Encoding: 7bit
|
||||
|
||||
Your follow up for (Ticket#1705265400361) has been received and will be reviewed by our support staff.
|
||||
|
||||
To provide additional information, please reply to this email or click on the following link:[1] https://example.zammad.loc/#ticket/zoom/232
|
||||
|
||||
Your Twelve SaaS Helpdesk Team
|
||||
|
||||
[2] Zammad, your customer support system
|
||||
|
||||
[1] https://example.zammad.loc/#ticket/zoom/232
|
||||
[2] https://zammad.com
|
||||
----==_mimepart_592843594d35_22d4208650435394
|
||||
Content-Type: multipart/related;
|
||||
boundary="--==_mimepart_592843594e47_22d4208650435484";
|
||||
charset=UTF-8
|
||||
Content-Transfer-Encoding: 7bit
|
||||
|
||||
|
||||
----==_mimepart_592843594e47_22d4208650435484
|
||||
Content-Type: text/html;
|
||||
charset=UTF-8
|
||||
Content-Transfer-Encoding: 7bit
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
|
||||
<style type="text/css">
|
||||
body {
|
||||
font-family:'Helvetica Neue', Helvetica, Arial, Geneva, sans-serif; font-size: 12px;;
|
||||
}
|
||||
img {
|
||||
outline: none;
|
||||
text-decoration: none;
|
||||
-ms-interpolation-mode: bicubic;
|
||||
}
|
||||
a img {
|
||||
border: none;
|
||||
}
|
||||
table td {
|
||||
border-collapse: collapse;
|
||||
}
|
||||
table {
|
||||
border-collapse: collapse;
|
||||
mso-table-lspace: 0pt;
|
||||
mso-table-rspace: 0pt;
|
||||
border: none;
|
||||
table-layout: auto;
|
||||
display: block;
|
||||
width: 100%;
|
||||
overflow: auto;
|
||||
word-break: keep-all;
|
||||
}
|
||||
table,
|
||||
pre,
|
||||
blockquote {
|
||||
margin: 0 0 16px;
|
||||
}
|
||||
td, th {
|
||||
padding: 7px 12px;
|
||||
border: 1px solid hsl(0,0%,87%);
|
||||
}
|
||||
th {
|
||||
font-weight: bold;
|
||||
text-align: center;
|
||||
}
|
||||
tbody tr:nth-child(even) {
|
||||
background: hsl(0,0%,97%);
|
||||
}
|
||||
col {
|
||||
width: auto;
|
||||
}
|
||||
p {
|
||||
margin: 0;
|
||||
}
|
||||
code {
|
||||
border: none;
|
||||
background: hsl(0,0%,97%);
|
||||
white-space: pre-wrap;
|
||||
}
|
||||
blockquote {
|
||||
padding: 8px 12px;
|
||||
border-left: 5px solid #eee;
|
||||
}
|
||||
pre {
|
||||
padding: 12px 15px;
|
||||
font-size: 13px;
|
||||
line-height: 1.45;
|
||||
background: hsl(0,0%,97%);
|
||||
white-space: pre-wrap;
|
||||
border-radius: 3px;
|
||||
border: none;
|
||||
overflow: auto;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body style="font-family:'Helvetica Neue', Helvetica, Arial, Geneva, sans-serif; font-size: 12px;"><div>Your follow up for <b>(Ticket#1705265400361)</b> has been received and will be reviewed by our support staff.</div>
|
||||
<br>
|
||||
<div>To provide additional information, please reply to this email or click on the following link:
|
||||
<a href="https://example.zammad.loc/#ticket/zoom/232" rel="nofollow noreferrer noopener" target="_blank">https://example.zammad.loc/#ticket/zoom/232</a>
|
||||
</div>
|
||||
<br>
|
||||
<div>Your Twelve SaaS Helpdesk Team</div>
|
||||
<br>
|
||||
<div><i><a href="https://zammad.com" rel="nofollow noreferrer noopener" target="_blank">Zammad</a>, your customer support system</i></div></body>
|
||||
</html>
|
||||
|
||||
----==_mimepart_592843594e47_22d4208650435484--
|
||||
|
||||
----==_mimepart_592843594d35_22d4208650435394--
|
||||
|
||||
----==_mimepart_5928435950b1_22d42086504355bc--
|
||||
|
||||
--207FF20398ED.1495810905/mx1.zammad.loc--
|
220
test/unit/email_process_bounce_delivery_permanent_failed_test.rb
Normal file
220
test/unit/email_process_bounce_delivery_permanent_failed_test.rb
Normal file
|
@ -0,0 +1,220 @@
|
|||
# encoding: utf-8
|
||||
require 'test_helper'
|
||||
|
||||
class EmailProcessBounceDeliveryPermanentFailedTest < ActiveSupport::TestCase
|
||||
|
||||
test 'process with bounce trigger email loop check - article based blocker' do
|
||||
roles = Role.where(name: %w(Customer))
|
||||
customer1 = User.create_or_update(
|
||||
login: 'ticket-bounce-trigger1@example.com',
|
||||
firstname: 'Notification',
|
||||
lastname: 'Customer1',
|
||||
email: 'ticket-bounce-trigger1@example.com',
|
||||
active: true,
|
||||
roles: roles,
|
||||
preferences: {},
|
||||
updated_by_id: 1,
|
||||
created_by_id: 1,
|
||||
)
|
||||
|
||||
Trigger.create_or_update(
|
||||
name: 'auto reply new ticket',
|
||||
condition: {
|
||||
'ticket.action' => {
|
||||
'operator' => 'is',
|
||||
'value' => 'create',
|
||||
},
|
||||
},
|
||||
perform: {
|
||||
'notification.email' => {
|
||||
'body' => 'some text<br>#{ticket.customer.lastname}<br>#{ticket.title}<br>#{article.body}',
|
||||
'recipient' => 'ticket_customer',
|
||||
'subject' => 'Thanks for your inquiry (#{ticket.title})!',
|
||||
},
|
||||
},
|
||||
disable_notification: true,
|
||||
active: true,
|
||||
created_by_id: 1,
|
||||
updated_by_id: 1,
|
||||
)
|
||||
Trigger.create_or_update(
|
||||
name: 'auto reply followup',
|
||||
condition: {
|
||||
'ticket.action' => {
|
||||
'operator' => 'is',
|
||||
'value' => 'update',
|
||||
},
|
||||
},
|
||||
perform: {
|
||||
'notification.email' => {
|
||||
'body' => 'some text<br>#{ticket.customer.lastname}<br>#{ticket.title}<br>#{article.body}',
|
||||
'recipient' => 'ticket_customer',
|
||||
'subject' => 'Thanks for your follow up (#{ticket.title})!',
|
||||
},
|
||||
},
|
||||
disable_notification: true,
|
||||
active: true,
|
||||
created_by_id: 1,
|
||||
updated_by_id: 1,
|
||||
)
|
||||
|
||||
ticket = Ticket.create(
|
||||
title: 'bounce check',
|
||||
group: Group.lookup(name: 'Users'),
|
||||
customer: customer1,
|
||||
state: Ticket::State.lookup(name: 'new'),
|
||||
priority: Ticket::Priority.lookup(name: '2 normal'),
|
||||
updated_by_id: 1,
|
||||
created_by_id: 1,
|
||||
)
|
||||
article = Ticket::Article.create(
|
||||
ticket_id: ticket.id,
|
||||
from: 'some_sender@example.com',
|
||||
to: 'some_recipient@example.com',
|
||||
subject: 'bounce check',
|
||||
message_id: '<20150830145601.30.6088xx@edenhofer.zammad.com>',
|
||||
body: 'some message bounce check',
|
||||
internal: false,
|
||||
sender: Ticket::Article::Sender.where(name: 'Agent').first,
|
||||
type: Ticket::Article::Type.where(name: 'email').first,
|
||||
updated_by_id: 1,
|
||||
created_by_id: 1,
|
||||
)
|
||||
Observer::Transaction.commit
|
||||
assert_equal('new', ticket.state.name)
|
||||
assert_equal(2, ticket.articles.count)
|
||||
|
||||
article = Ticket::Article.create(
|
||||
ticket_id: ticket.id,
|
||||
from: 'some_sender@example.com',
|
||||
to: customer1.email,
|
||||
subject: 'bounce check 2',
|
||||
message_id: '<20150830145601.30.608881@edenhofer.zammad.com>',
|
||||
body: 'some message bounce check 2',
|
||||
internal: false,
|
||||
sender: Ticket::Article::Sender.where(name: 'Agent').first,
|
||||
type: Ticket::Article::Type.where(name: 'email').first,
|
||||
updated_by_id: 1,
|
||||
created_by_id: 1,
|
||||
)
|
||||
Observer::Transaction.commit
|
||||
assert_equal(4, ticket.articles.count)
|
||||
|
||||
travel 1.second
|
||||
email_raw_string = IO.binread('test/fixtures/mail33-undelivered-mail-returned-to-sender.box')
|
||||
ticket_p, article_p, user_p = Channel::EmailParser.new.process({}, email_raw_string)
|
||||
assert_equal(ticket.id, ticket_p.id)
|
||||
assert_equal('open', ticket_p.state.name)
|
||||
assert_equal(5, ticket_p.articles.count)
|
||||
travel_back
|
||||
ticket.destroy
|
||||
end
|
||||
|
||||
test 'process with bounce trigger email loop check - bounce based blocker' do
|
||||
roles = Role.where(name: %w(Customer))
|
||||
customer2 = User.create_or_update(
|
||||
login: 'ticket-bounce-trigger2@example.com',
|
||||
firstname: 'Notification',
|
||||
lastname: 'Customer2',
|
||||
email: 'ticket-bounce-trigger2@example.com',
|
||||
active: true,
|
||||
roles: roles,
|
||||
preferences: {},
|
||||
updated_by_id: 1,
|
||||
created_by_id: 1,
|
||||
)
|
||||
|
||||
Trigger.create_or_update(
|
||||
name: 'auto reply new ticket',
|
||||
condition: {
|
||||
'ticket.action' => {
|
||||
'operator' => 'is',
|
||||
'value' => 'create',
|
||||
},
|
||||
},
|
||||
perform: {
|
||||
'notification.email' => {
|
||||
'body' => 'some text<br>#{ticket.customer.lastname}<br>#{ticket.title}<br>#{article.body}',
|
||||
'recipient' => 'ticket_customer',
|
||||
'subject' => 'Thanks for your inquiry (#{ticket.title})!',
|
||||
},
|
||||
},
|
||||
disable_notification: true,
|
||||
active: true,
|
||||
created_by_id: 1,
|
||||
updated_by_id: 1,
|
||||
)
|
||||
Trigger.create_or_update(
|
||||
name: 'auto reply followup',
|
||||
condition: {
|
||||
'ticket.action' => {
|
||||
'operator' => 'is',
|
||||
'value' => 'update',
|
||||
},
|
||||
},
|
||||
perform: {
|
||||
'notification.email' => {
|
||||
'body' => 'some text<br>#{ticket.customer.lastname}<br>#{ticket.title}<br>#{article.body}',
|
||||
'recipient' => 'ticket_customer',
|
||||
'subject' => 'Thanks for your follow up (#{ticket.title})!',
|
||||
},
|
||||
},
|
||||
disable_notification: true,
|
||||
active: true,
|
||||
created_by_id: 1,
|
||||
updated_by_id: 1,
|
||||
)
|
||||
|
||||
ticket = Ticket.create(
|
||||
title: 'bounce check',
|
||||
group: Group.lookup(name: 'Users'),
|
||||
customer: customer2,
|
||||
state: Ticket::State.lookup(name: 'new'),
|
||||
priority: Ticket::Priority.lookup(name: '2 normal'),
|
||||
updated_by_id: 1,
|
||||
created_by_id: 1,
|
||||
)
|
||||
article = Ticket::Article.create(
|
||||
ticket_id: ticket.id,
|
||||
from: 'some_sender@example.com',
|
||||
to: 'some_recipient@example.com',
|
||||
subject: 'bounce check',
|
||||
message_id: '<20150830145601.30.6088xx@edenhofer.zammad.com>',
|
||||
body: 'some message bounce check',
|
||||
internal: false,
|
||||
sender: Ticket::Article::Sender.where(name: 'Agent').first,
|
||||
type: Ticket::Article::Type.where(name: 'email').first,
|
||||
updated_by_id: 1,
|
||||
created_by_id: 1,
|
||||
)
|
||||
Observer::Transaction.commit
|
||||
assert_equal('new', ticket.state.name)
|
||||
assert_equal(2, ticket.articles.count)
|
||||
|
||||
article = Ticket::Article.create(
|
||||
ticket_id: ticket.id,
|
||||
from: 'some_sender@example.com',
|
||||
to: 'some_recipient@example.com',
|
||||
subject: 'bounce check 2',
|
||||
message_id: '<20170526150141.232.13312@example.zammad.loc>',
|
||||
body: 'some message bounce check 2',
|
||||
internal: false,
|
||||
sender: Ticket::Article::Sender.where(name: 'Agent').first,
|
||||
type: Ticket::Article::Type.where(name: 'email').first,
|
||||
updated_by_id: 1,
|
||||
created_by_id: 1,
|
||||
)
|
||||
Observer::Transaction.commit
|
||||
assert_equal(4, ticket.articles.count)
|
||||
|
||||
travel 1.second
|
||||
email_raw_string = IO.binread('test/fixtures/mail55.box')
|
||||
ticket_p, article_p, user_p = Channel::EmailParser.new.process({}, email_raw_string)
|
||||
assert_equal(ticket.id, ticket_p.id)
|
||||
assert_equal('open', ticket_p.state.name)
|
||||
assert_equal(5, ticket_p.articles.count)
|
||||
travel_back
|
||||
ticket.destroy
|
||||
end
|
||||
|
||||
end
|
254
test/unit/email_process_bounce_follow_test.rb
Normal file
254
test/unit/email_process_bounce_follow_test.rb
Normal file
|
@ -0,0 +1,254 @@
|
|||
# encoding: utf-8
|
||||
require 'test_helper'
|
||||
|
||||
class EmailProcessBounceFollowUpTest < ActiveSupport::TestCase
|
||||
|
||||
test 'process with bounce follow up check' do
|
||||
|
||||
ticket = Ticket.create(
|
||||
title: 'bounce check',
|
||||
group: Group.lookup(name: 'Users'),
|
||||
customer_id: 2,
|
||||
state: Ticket::State.lookup(name: 'new'),
|
||||
priority: Ticket::Priority.lookup(name: '2 normal'),
|
||||
updated_by_id: 1,
|
||||
created_by_id: 1,
|
||||
)
|
||||
article = Ticket::Article.create(
|
||||
ticket_id: ticket.id,
|
||||
from: 'some_sender@example.com',
|
||||
to: 'some_recipient@example.com',
|
||||
subject: 'bounce check',
|
||||
message_id: '<20150830145601.30.608881@edenhofer.zammad.com>',
|
||||
body: 'some message bounce check',
|
||||
internal: false,
|
||||
sender: Ticket::Article::Sender.where(name: 'Customer').first,
|
||||
type: Ticket::Article::Type.where(name: 'email').first,
|
||||
updated_by_id: 1,
|
||||
created_by_id: 1,
|
||||
)
|
||||
travel 1.second
|
||||
email_raw_string = IO.binread('test/fixtures/mail33-undelivered-mail-returned-to-sender.box')
|
||||
ticket_p, article_p, user_p = Channel::EmailParser.new.process({}, email_raw_string)
|
||||
assert_equal(ticket.id, ticket_p.id)
|
||||
assert_equal('new', ticket_p.state.name)
|
||||
travel_back
|
||||
ticket.destroy
|
||||
|
||||
end
|
||||
|
||||
test 'process with bounce trigger email loop check - article based blocker' do
|
||||
roles = Role.where(name: %w(Customer))
|
||||
customer1 = User.create_or_update(
|
||||
login: 'ticket-bounce-trigger1@example.com',
|
||||
firstname: 'Notification',
|
||||
lastname: 'Customer1',
|
||||
email: 'ticket-bounce-trigger1@example.com',
|
||||
active: true,
|
||||
roles: roles,
|
||||
preferences: {},
|
||||
updated_by_id: 1,
|
||||
created_by_id: 1,
|
||||
)
|
||||
|
||||
Trigger.create_or_update(
|
||||
name: 'auto reply new ticket',
|
||||
condition: {
|
||||
'ticket.action' => {
|
||||
'operator' => 'is',
|
||||
'value' => 'create',
|
||||
},
|
||||
},
|
||||
perform: {
|
||||
'notification.email' => {
|
||||
'body' => 'some text<br>#{ticket.customer.lastname}<br>#{ticket.title}<br>#{article.body}',
|
||||
'recipient' => 'ticket_customer',
|
||||
'subject' => 'Thanks for your inquiry (#{ticket.title})!',
|
||||
},
|
||||
},
|
||||
disable_notification: true,
|
||||
active: true,
|
||||
created_by_id: 1,
|
||||
updated_by_id: 1,
|
||||
)
|
||||
Trigger.create_or_update(
|
||||
name: 'auto reply followup',
|
||||
condition: {
|
||||
'ticket.action' => {
|
||||
'operator' => 'is',
|
||||
'value' => 'update',
|
||||
},
|
||||
},
|
||||
perform: {
|
||||
'notification.email' => {
|
||||
'body' => 'some text<br>#{ticket.customer.lastname}<br>#{ticket.title}<br>#{article.body}',
|
||||
'recipient' => 'ticket_customer',
|
||||
'subject' => 'Thanks for your follow up (#{ticket.title})!',
|
||||
},
|
||||
},
|
||||
disable_notification: true,
|
||||
active: true,
|
||||
created_by_id: 1,
|
||||
updated_by_id: 1,
|
||||
)
|
||||
|
||||
ticket = Ticket.create(
|
||||
title: 'bounce check',
|
||||
group: Group.lookup(name: 'Users'),
|
||||
customer: customer1,
|
||||
state: Ticket::State.lookup(name: 'new'),
|
||||
priority: Ticket::Priority.lookup(name: '2 normal'),
|
||||
updated_by_id: 1,
|
||||
created_by_id: 1,
|
||||
)
|
||||
article = Ticket::Article.create(
|
||||
ticket_id: ticket.id,
|
||||
from: 'some_sender@example.com',
|
||||
to: 'some_recipient@example.com',
|
||||
subject: 'bounce check',
|
||||
message_id: '<20150830145601.30.6088xx@edenhofer.zammad.com>',
|
||||
body: 'some message bounce check',
|
||||
internal: false,
|
||||
sender: Ticket::Article::Sender.where(name: 'Agent').first,
|
||||
type: Ticket::Article::Type.where(name: 'email').first,
|
||||
updated_by_id: 1,
|
||||
created_by_id: 1,
|
||||
)
|
||||
Observer::Transaction.commit
|
||||
assert_equal('new', ticket.state.name)
|
||||
assert_equal(2, ticket.articles.count)
|
||||
|
||||
article = Ticket::Article.create(
|
||||
ticket_id: ticket.id,
|
||||
from: 'some_sender@example.com',
|
||||
to: customer1.email,
|
||||
subject: 'bounce check 2',
|
||||
message_id: '<20150830145601.30.608881@edenhofer.zammad.com>',
|
||||
body: 'some message bounce check 2',
|
||||
internal: false,
|
||||
sender: Ticket::Article::Sender.where(name: 'Agent').first,
|
||||
type: Ticket::Article::Type.where(name: 'email').first,
|
||||
updated_by_id: 1,
|
||||
created_by_id: 1,
|
||||
)
|
||||
Observer::Transaction.commit
|
||||
assert_equal(4, ticket.articles.count)
|
||||
|
||||
travel 1.second
|
||||
email_raw_string = IO.binread('test/fixtures/mail33-undelivered-mail-returned-to-sender.box')
|
||||
ticket_p, article_p, user_p = Channel::EmailParser.new.process({}, email_raw_string)
|
||||
assert_equal(ticket.id, ticket_p.id)
|
||||
assert_equal('open', ticket_p.state.name)
|
||||
assert_equal(5, ticket_p.articles.count)
|
||||
travel_back
|
||||
ticket.destroy
|
||||
end
|
||||
|
||||
test 'process with bounce trigger email loop check - bounce based blocker' do
|
||||
roles = Role.where(name: %w(Customer))
|
||||
customer2 = User.create_or_update(
|
||||
login: 'ticket-bounce-trigger2@example.com',
|
||||
firstname: 'Notification',
|
||||
lastname: 'Customer2',
|
||||
email: 'ticket-bounce-trigger2@example.com',
|
||||
active: true,
|
||||
roles: roles,
|
||||
preferences: {},
|
||||
updated_by_id: 1,
|
||||
created_by_id: 1,
|
||||
)
|
||||
|
||||
Trigger.create_or_update(
|
||||
name: 'auto reply new ticket',
|
||||
condition: {
|
||||
'ticket.action' => {
|
||||
'operator' => 'is',
|
||||
'value' => 'create',
|
||||
},
|
||||
},
|
||||
perform: {
|
||||
'notification.email' => {
|
||||
'body' => 'some text<br>#{ticket.customer.lastname}<br>#{ticket.title}<br>#{article.body}',
|
||||
'recipient' => 'ticket_customer',
|
||||
'subject' => 'Thanks for your inquiry (#{ticket.title})!',
|
||||
},
|
||||
},
|
||||
disable_notification: true,
|
||||
active: true,
|
||||
created_by_id: 1,
|
||||
updated_by_id: 1,
|
||||
)
|
||||
Trigger.create_or_update(
|
||||
name: 'auto reply followup',
|
||||
condition: {
|
||||
'ticket.action' => {
|
||||
'operator' => 'is',
|
||||
'value' => 'update',
|
||||
},
|
||||
},
|
||||
perform: {
|
||||
'notification.email' => {
|
||||
'body' => 'some text<br>#{ticket.customer.lastname}<br>#{ticket.title}<br>#{article.body}',
|
||||
'recipient' => 'ticket_customer',
|
||||
'subject' => 'Thanks for your follow up (#{ticket.title})!',
|
||||
},
|
||||
},
|
||||
disable_notification: true,
|
||||
active: true,
|
||||
created_by_id: 1,
|
||||
updated_by_id: 1,
|
||||
)
|
||||
|
||||
ticket = Ticket.create(
|
||||
title: 'bounce check',
|
||||
group: Group.lookup(name: 'Users'),
|
||||
customer: customer2,
|
||||
state: Ticket::State.lookup(name: 'new'),
|
||||
priority: Ticket::Priority.lookup(name: '2 normal'),
|
||||
updated_by_id: 1,
|
||||
created_by_id: 1,
|
||||
)
|
||||
article = Ticket::Article.create(
|
||||
ticket_id: ticket.id,
|
||||
from: 'some_sender@example.com',
|
||||
to: 'some_recipient@example.com',
|
||||
subject: 'bounce check',
|
||||
message_id: '<20150830145601.30.6088xx@edenhofer.zammad.com>',
|
||||
body: 'some message bounce check',
|
||||
internal: false,
|
||||
sender: Ticket::Article::Sender.where(name: 'Agent').first,
|
||||
type: Ticket::Article::Type.where(name: 'email').first,
|
||||
updated_by_id: 1,
|
||||
created_by_id: 1,
|
||||
)
|
||||
Observer::Transaction.commit
|
||||
assert_equal('new', ticket.state.name)
|
||||
assert_equal(2, ticket.articles.count)
|
||||
|
||||
article = Ticket::Article.create(
|
||||
ticket_id: ticket.id,
|
||||
from: 'some_sender@example.com',
|
||||
to: 'some_recipient@example.com',
|
||||
subject: 'bounce check 2',
|
||||
message_id: '<20170526150141.232.13312@example.zammad.loc>',
|
||||
body: 'some message bounce check 2',
|
||||
internal: false,
|
||||
sender: Ticket::Article::Sender.where(name: 'Agent').first,
|
||||
type: Ticket::Article::Type.where(name: 'email').first,
|
||||
updated_by_id: 1,
|
||||
created_by_id: 1,
|
||||
)
|
||||
Observer::Transaction.commit
|
||||
assert_equal(4, ticket.articles.count)
|
||||
|
||||
travel 1.second
|
||||
email_raw_string = IO.binread('test/fixtures/mail55.box')
|
||||
ticket_p, article_p, user_p = Channel::EmailParser.new.process({}, email_raw_string)
|
||||
assert_equal(ticket.id, ticket_p.id)
|
||||
assert_equal('open', ticket_p.state.name)
|
||||
assert_equal(5, ticket_p.articles.count)
|
||||
travel_back
|
||||
ticket.destroy
|
||||
end
|
||||
|
||||
end
|
|
@ -1,39 +0,0 @@
|
|||
# encoding: utf-8
|
||||
require 'test_helper'
|
||||
|
||||
class EmailProcessBounceTest < ActiveSupport::TestCase
|
||||
|
||||
test 'process with bounce check' do
|
||||
|
||||
ticket = Ticket.create(
|
||||
title: 'bounce check',
|
||||
group: Group.lookup( name: 'Users'),
|
||||
customer_id: 2,
|
||||
state: Ticket::State.lookup( name: 'new' ),
|
||||
priority: Ticket::Priority.lookup( name: '2 normal' ),
|
||||
updated_by_id: 1,
|
||||
created_by_id: 1,
|
||||
)
|
||||
article = Ticket::Article.create(
|
||||
ticket_id: ticket.id,
|
||||
from: 'some_sender@example.com',
|
||||
to: 'some_recipient@example.com',
|
||||
subject: 'bounce check',
|
||||
message_id: '<20150830145601.30.608881@edenhofer.zammad.com>',
|
||||
body: 'some message bounce check',
|
||||
internal: false,
|
||||
sender: Ticket::Article::Sender.where(name: 'Customer').first,
|
||||
type: Ticket::Article::Type.where(name: 'email').first,
|
||||
updated_by_id: 1,
|
||||
created_by_id: 1,
|
||||
)
|
||||
travel 1.second
|
||||
email_raw_string = IO.binread('test/fixtures/mail33-undelivered-mail-returned-to-sender.box')
|
||||
ticket_p, article_p, user_p = Channel::EmailParser.new.process({}, email_raw_string)
|
||||
assert_equal(ticket.id, ticket_p.id)
|
||||
assert_equal('new', ticket_p.state.name)
|
||||
travel_back
|
||||
ticket.destroy
|
||||
end
|
||||
|
||||
end
|
Loading…
Reference in a new issue