Implemented reply_to header as sender/customer feature.
This commit is contained in:
parent
e9efae4b83
commit
79c398becb
5 changed files with 254 additions and 26 deletions
|
@ -117,32 +117,7 @@ class Channel::EmailParser
|
|||
}
|
||||
|
||||
# set extra headers
|
||||
begin
|
||||
data[:from_email] = Mail::Address.new(from).address
|
||||
data[:from_local] = Mail::Address.new(from).local
|
||||
data[:from_domain] = Mail::Address.new(from).domain
|
||||
data[:from_display_name] = Mail::Address.new(from).display_name ||
|
||||
(Mail::Address.new(from).comments && Mail::Address.new(from).comments[0])
|
||||
rescue
|
||||
from.strip!
|
||||
if from =~ /^(.+?)<(.+?)@(.+?)>$/
|
||||
data[:from_email] = "#{$2}@#{$3}"
|
||||
data[:from_local] = $2
|
||||
data[:from_domain] = $3
|
||||
data[:from_display_name] = $1
|
||||
else
|
||||
data[:from_email] = from
|
||||
data[:from_local] = from
|
||||
data[:from_domain] = from
|
||||
end
|
||||
end
|
||||
|
||||
# do extra decoding because we needed to use field.value
|
||||
data[:from_display_name] = Mail::Field.new('X-From', data[:from_display_name]).to_s
|
||||
data[:from_display_name].delete!('"')
|
||||
data[:from_display_name].strip!
|
||||
data[:from_display_name].gsub!(/^'/, '')
|
||||
data[:from_display_name].gsub!(/'$/, '')
|
||||
data = data.merge(Channel::EmailParser.sender_properties(from))
|
||||
|
||||
# do extra encoding (see issue#1045)
|
||||
if data[:subject].present?
|
||||
|
@ -638,6 +613,39 @@ returns
|
|||
true
|
||||
end
|
||||
|
||||
def self.sender_properties(from)
|
||||
data = {}
|
||||
|
||||
begin
|
||||
data[:from_email] = Mail::Address.new(from).address
|
||||
data[:from_local] = Mail::Address.new(from).local
|
||||
data[:from_domain] = Mail::Address.new(from).domain
|
||||
data[:from_display_name] = Mail::Address.new(from).display_name ||
|
||||
(Mail::Address.new(from).comments && Mail::Address.new(from).comments[0])
|
||||
rescue
|
||||
from.strip!
|
||||
if from =~ /^(.+?)<(.+?)@(.+?)>$/
|
||||
data[:from_email] = "#{$2}@#{$3}"
|
||||
data[:from_local] = $2
|
||||
data[:from_domain] = $3
|
||||
data[:from_display_name] = $1
|
||||
else
|
||||
data[:from_email] = from
|
||||
data[:from_local] = from
|
||||
data[:from_domain] = from
|
||||
end
|
||||
end
|
||||
|
||||
# do extra decoding because we needed to use field.value
|
||||
data[:from_display_name] = Mail::Field.new('X-From', data[:from_display_name]).to_s
|
||||
data[:from_display_name].delete!('"')
|
||||
data[:from_display_name].strip!
|
||||
data[:from_display_name].gsub!(/^'/, '')
|
||||
data[:from_display_name].gsub!(/'$/, '')
|
||||
|
||||
data
|
||||
end
|
||||
|
||||
def set_attributes_by_x_headers(item_object, header_name, mail, suffix = false)
|
||||
|
||||
# loop all x-zammad-hedaer-* headers
|
||||
|
|
36
app/models/channel/filter/reply_to_based_sender.rb
Normal file
36
app/models/channel/filter/reply_to_based_sender.rb
Normal file
|
@ -0,0 +1,36 @@
|
|||
# Copyright (C) 2012-2016 Zammad Foundation, http://zammad-foundation.org/
|
||||
|
||||
module Channel::Filter::ReplyToBasedSender
|
||||
|
||||
def self.run(_channel, mail)
|
||||
|
||||
reply_to = mail['reply-to'.to_sym]
|
||||
return if reply_to.blank?
|
||||
|
||||
setting = Setting.get('postmaster_sender_based_on_reply_to')
|
||||
return if setting.blank?
|
||||
|
||||
# get properties of reply-to header
|
||||
result = Channel::EmailParser.sender_properties(reply_to)
|
||||
|
||||
if setting == 'as_sender_of_email'
|
||||
mail[:from] = reply_to
|
||||
mail[:from_email] = result[:from_email]
|
||||
mail[:from_local] = result[:from_local]
|
||||
mail[:from_domain] = result[:from_domain]
|
||||
mail[:from_display_name] = result[:from_display_name]
|
||||
return
|
||||
end
|
||||
|
||||
if setting == 'as_sender_of_email_use_from_realname'
|
||||
mail[:from] = reply_to
|
||||
mail[:from_email] = result[:from_email]
|
||||
mail[:from_local] = result[:from_local]
|
||||
mail[:from_domain] = result[:from_domain]
|
||||
return
|
||||
end
|
||||
|
||||
Rails.logger.error "Invalid setting value for 'postmaster_sender_based_on_reply_to' -> #{setting.inspect}"
|
||||
end
|
||||
|
||||
end
|
45
db/migrate/20170525000001_reply_to_sender_feature.rb
Normal file
45
db/migrate/20170525000001_reply_to_sender_feature.rb
Normal file
|
@ -0,0 +1,45 @@
|
|||
class ReplyToSenderFeature < ActiveRecord::Migration
|
||||
def up
|
||||
|
||||
# return if it's a new setup
|
||||
return if !Setting.find_by(name: 'system_init_done')
|
||||
|
||||
Setting.create_if_not_exists(
|
||||
title: 'Sender based on Reply-To header',
|
||||
name: 'postmaster_sender_based_on_reply_to',
|
||||
area: 'Email::Base',
|
||||
description: 'Set/overwrite sender/from of email based on reply-to header. Useful to set correct customer if email is received from a third party system on behalf of a customer.',
|
||||
options: {
|
||||
form: [
|
||||
{
|
||||
display: '',
|
||||
null: true,
|
||||
name: 'postmaster_sender_based_on_reply_to',
|
||||
tag: 'select',
|
||||
options: {
|
||||
'' => '-',
|
||||
'as_sender_of_email' => 'Take reply-to header as sender/from of email.',
|
||||
'as_sender_of_email_use_from_realname' => 'Take reply-to header as sender/from of email and use realname of origin from.',
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
state: [],
|
||||
preferences: {
|
||||
permission: ['admin.channel_email'],
|
||||
},
|
||||
frontend: false
|
||||
)
|
||||
|
||||
Setting.create_if_not_exists(
|
||||
title: 'Defines postmaster filter.',
|
||||
name: '0011_postmaster_sender_based_on_reply_to',
|
||||
area: 'Postmaster::PreFilter',
|
||||
description: 'Defines postmaster filter to set the sender/from of emails based on reply-to header.',
|
||||
options: {},
|
||||
state: 'Channel::Filter::ReplyToBasedSender',
|
||||
frontend: false
|
||||
)
|
||||
end
|
||||
|
||||
end
|
|
@ -1657,6 +1657,33 @@ Setting.create_if_not_exists(
|
|||
frontend: false
|
||||
)
|
||||
|
||||
Setting.create_if_not_exists(
|
||||
title: 'Sender based on Reply-To header',
|
||||
name: 'postmaster_sender_based_on_reply_to',
|
||||
area: 'Email::Base',
|
||||
description: 'Set/overwrite sender/from of email based on reply-to header. Useful to set correct customer if email is received from a third party system on behalf of a customer.',
|
||||
options: {
|
||||
form: [
|
||||
{
|
||||
display: '',
|
||||
null: true,
|
||||
name: 'postmaster_sender_based_on_reply_to',
|
||||
tag: 'select',
|
||||
options: {
|
||||
'' => '-',
|
||||
'as_sender_of_email' => 'Take reply-to header as sender/from of email.',
|
||||
'as_sender_of_email_use_from_realname' => 'Take reply-to header as sender/from of email and use realname of origin from.',
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
state: [],
|
||||
preferences: {
|
||||
permission: ['admin.channel_email'],
|
||||
},
|
||||
frontend: false
|
||||
)
|
||||
|
||||
Setting.create_if_not_exists(
|
||||
title: 'Notification Sender',
|
||||
name: 'notification_sender',
|
||||
|
@ -2217,6 +2244,15 @@ Setting.create_if_not_exists(
|
|||
state: 'Channel::Filter::Trusted',
|
||||
frontend: false
|
||||
)
|
||||
Setting.create_if_not_exists(
|
||||
title: 'Defines postmaster filter.',
|
||||
name: '0011_postmaster_sender_based_on_reply_to',
|
||||
area: 'Postmaster::PreFilter',
|
||||
description: 'Defines postmaster filter to set the sender/from of emails based on reply-to header.',
|
||||
options: {},
|
||||
state: 'Channel::Filter::ReplyToBasedSender',
|
||||
frontend: false
|
||||
)
|
||||
Setting.create_if_not_exists(
|
||||
title: 'Defines postmaster filter.',
|
||||
name: '0012_postmaster_filter_sender_is_system_address',
|
||||
|
|
103
test/unit/email_process_reply_to_test.rb
Normal file
103
test/unit/email_process_reply_to_test.rb
Normal file
|
@ -0,0 +1,103 @@
|
|||
# encoding: utf-8
|
||||
require 'test_helper'
|
||||
|
||||
class EmailProcessReplyToTest < ActiveSupport::TestCase
|
||||
|
||||
test 'normal processing' do
|
||||
|
||||
setting_orig = Setting.get('postmaster_sender_based_on_reply_to')
|
||||
Setting.set('postmaster_sender_based_on_reply_to', '')
|
||||
|
||||
email = "From: Bob Smith <marketing_tool@example.com>
|
||||
To: zammad@example.com
|
||||
Subject: some new subject
|
||||
Reply-To: replay_to_customer_process1@example.com
|
||||
|
||||
Some Text"
|
||||
|
||||
ticket_p, article_p, user_p = Channel::EmailParser.new.process({}, email)
|
||||
assert_equal('Bob Smith <marketing_tool@example.com>', article_p.from)
|
||||
assert_equal('replay_to_customer_process1@example.com', article_p.reply_to)
|
||||
assert_equal('marketing_tool@example.com', ticket_p.customer.email)
|
||||
assert_equal('Bob', ticket_p.customer.firstname)
|
||||
assert_equal('Smith', ticket_p.customer.lastname)
|
||||
|
||||
Setting.set('postmaster_sender_based_on_reply_to', setting_orig)
|
||||
|
||||
end
|
||||
|
||||
test 'normal processing - take reply to as customer' do
|
||||
|
||||
setting_orig = Setting.get('postmaster_sender_based_on_reply_to')
|
||||
Setting.set('postmaster_sender_based_on_reply_to', 'as_sender_of_email')
|
||||
|
||||
email = "From: Bob Smith <marketing_tool@example.com>
|
||||
To: zammad@example.com
|
||||
Subject: some new subject
|
||||
Reply-To: replay_to_customer_process2@example.com
|
||||
|
||||
Some Text"
|
||||
|
||||
ticket_p, article_p, user_p = Channel::EmailParser.new.process({}, email)
|
||||
assert_equal('replay_to_customer_process2@example.com', article_p.from)
|
||||
assert_equal('replay_to_customer_process2@example.com', article_p.reply_to)
|
||||
assert_equal('replay_to_customer_process2@example.com', ticket_p.customer.email)
|
||||
assert_equal('', ticket_p.customer.firstname)
|
||||
assert_equal('', ticket_p.customer.lastname)
|
||||
|
||||
email = "From: Bob Smith <marketing_tool@example.com>
|
||||
To: zammad@example.com
|
||||
Subject: some new subject
|
||||
Reply-To: Some Name <replay_to_customer_process2-1@example.com>
|
||||
|
||||
Some Text"
|
||||
|
||||
ticket_p, article_p, user_p = Channel::EmailParser.new.process({}, email)
|
||||
assert_equal('Some Name <replay_to_customer_process2-1@example.com>', article_p.from)
|
||||
assert_equal('Some Name <replay_to_customer_process2-1@example.com>', article_p.reply_to)
|
||||
assert_equal('replay_to_customer_process2-1@example.com', ticket_p.customer.email)
|
||||
assert_equal('Some', ticket_p.customer.firstname)
|
||||
assert_equal('Name', ticket_p.customer.lastname)
|
||||
|
||||
Setting.set('postmaster_sender_based_on_reply_to', setting_orig)
|
||||
|
||||
end
|
||||
|
||||
test 'normal processing - take reply to as customer and use from as realname' do
|
||||
|
||||
setting_orig = Setting.get('postmaster_sender_based_on_reply_to')
|
||||
Setting.set('postmaster_sender_based_on_reply_to', 'as_sender_of_email_use_from_realname')
|
||||
|
||||
email = "From: Bob Smith <marketing_tool@example.com>
|
||||
To: zammad@example.com
|
||||
Subject: some new subject
|
||||
Reply-To: replay_to_customer_process3@example.com
|
||||
|
||||
Some Text"
|
||||
|
||||
ticket_p, article_p, user_p = Channel::EmailParser.new.process({}, email)
|
||||
assert_equal('replay_to_customer_process3@example.com', article_p.from)
|
||||
assert_equal('replay_to_customer_process3@example.com', article_p.reply_to)
|
||||
assert_equal('replay_to_customer_process3@example.com', ticket_p.customer.email)
|
||||
assert_equal('Bob', ticket_p.customer.firstname)
|
||||
assert_equal('Smith', ticket_p.customer.lastname)
|
||||
|
||||
email = "From: Bob Smith <marketing_tool@example.com>
|
||||
To: zammad@example.com
|
||||
Subject: some new subject
|
||||
Reply-To: Some Name <replay_to_customer_process3-1@example.com>
|
||||
|
||||
Some Text"
|
||||
|
||||
ticket_p, article_p, user_p = Channel::EmailParser.new.process({}, email)
|
||||
assert_equal('Some Name <replay_to_customer_process3-1@example.com>', article_p.from)
|
||||
assert_equal('Some Name <replay_to_customer_process3-1@example.com>', article_p.reply_to)
|
||||
assert_equal('replay_to_customer_process3-1@example.com', ticket_p.customer.email)
|
||||
assert_equal('Bob', ticket_p.customer.firstname)
|
||||
assert_equal('Smith', ticket_p.customer.lastname)
|
||||
|
||||
Setting.set('postmaster_sender_based_on_reply_to', setting_orig)
|
||||
|
||||
end
|
||||
|
||||
end
|
Loading…
Reference in a new issue