Remove quotation marks from email addresses (fixes #2154)

This commit is contained in:
Ryan Lue 2018-08-10 15:19:37 +08:00
parent f848f8d151
commit ae8fa91260
7 changed files with 97 additions and 37 deletions

View file

@ -30,11 +30,12 @@ class EmailReply extends App.Controller
# remove system addresses # remove system addresses
localAddresses = App.EmailAddress.all() localAddresses = App.EmailAddress.all()
forgeinRecipients = [] foreignRecipients = []
recipientUsed = {} recipientUsed = {}
for recipient in recipients for recipient in recipients
if !_.isEmpty(recipient.address) if !_.isEmpty(recipient.address)
localRecipientAddress = recipient.address.toString().toLowerCase() localRecipientAddress = recipient.address.toString().toLowerCase()
if !recipientUsed[localRecipientAddress] if !recipientUsed[localRecipientAddress]
recipientUsed[localRecipientAddress] = true recipientUsed[localRecipientAddress] = true
localAddress = false localAddress = false
@ -43,10 +44,10 @@ class EmailReply extends App.Controller
recipientUsed[localRecipientAddress] = true recipientUsed[localRecipientAddress] = true
localAddress = true localAddress = true
if !localAddress if !localAddress
forgeinRecipients.push recipient foreignRecipients.push recipient
# check if reply all is neede # check if reply all is neede
if forgeinRecipients.length > 1 if foreignRecipients.length > 1
actions.push { actions.push {
name: 'reply all' name: 'reply all'
type: 'emailReplyAll' type: 'emailReplyAll'

View file

@ -1034,32 +1034,20 @@ class App.Utils
# filter for uniq recipients # filter for uniq recipients
recipientAddresses = {} recipientAddresses = {}
addAddresses = (addressLine, line) -> addAddresses = (addressLine, line) ->
lineNew = ''
recipients = App.Utils.parseAddressListLocal(addressLine) recipients = App.Utils.parseAddressListLocal(addressLine)
if !_.isEmpty(recipients) recipients = recipients.map((r) -> r.toString().toLowerCase())
for recipient in recipients recipients = _.reject(recipients, (r) -> _.isEmpty(r))
if !_.isEmpty(recipient) recipients = _.reject(recipients, (r) -> isLocalAddress(r))
localRecipientAddress = recipient.toString().toLowerCase() recipients = _.reject(recipients, (r) -> recipientAddresses[r])
recipients = _.each(recipients, (r) -> recipientAddresses[r] = true)
# check if address is not local recipients.push(line) if !_.isEmpty(line)
if !isLocalAddress(localRecipientAddress)
# filter for uniq recipients # see https://github.com/zammad/zammad/issues/2154
if !recipientAddresses[localRecipientAddress] recipients = recipients.map((a) -> a.replace(/'(\S+@\S+\.\S+)'/, '$1'))
recipientAddresses[localRecipientAddress] = true
# add recipient recipients.join(', ')
if lineNew
lineNew = lineNew + ', '
lineNew = lineNew + localRecipientAddress
lineNew
if !_.isEmpty(line)
if !_.isEmpty(lineNew)
lineNew += ', '
lineNew += line
lineNew
if articleNew.to if articleNew.to
articleNew.to = addAddresses(articleNew.to) articleNew.to = addAddresses(articleNew.to)

View file

@ -491,14 +491,13 @@ process unprocessable_mails (tmp/unprocessable_mail/*.eml) again
# imported_fields = mail.header.fields.map { |f| [f.name.downcase, f.to_utf8] }.to_h # imported_fields = mail.header.fields.map { |f| [f.name.downcase, f.to_utf8] }.to_h
raw_fields = mail.header.fields.map { |f| ["raw-#{f.name.downcase}", f] }.to_h raw_fields = mail.header.fields.map { |f| ["raw-#{f.name.downcase}", f] }.to_h
custom_fields = {}.tap do |h| custom_fields = {}.tap do |h|
validated_recipients = imported_fields.slice(*RECIPIENT_FIELDS) h.replace(imported_fields.slice(*RECIPIENT_FIELDS)
.transform_values { |v| v.match?(EMAIL_REGEX) ? v : '' } .transform_values { |v| v.match?(EMAIL_REGEX) ? v : '' })
h.merge!(validated_recipients)
h['x-any-recipient'] = h.values.select(&:present?).join(', ')
h['date'] = Time.zone.parse(mail.date.to_s) || imported_fields['date'] h['date'] = Time.zone.parse(mail.date.to_s) || imported_fields['date']
h['message_id'] = imported_fields['message-id'] h['message_id'] = imported_fields['message-id']
h['subject'] = imported_fields['subject']&.sub(/^=\?us-ascii\?Q\?(.+)\?=$/, '\1') h['subject'] = imported_fields['subject']&.sub(/^=\?us-ascii\?Q\?(.+)\?=$/, '\1')
h['x-any-recipient'] = validated_recipients.values.select(&:present?).join(', ')
end end
[imported_fields, raw_fields, custom_fields].reduce({}.with_indifferent_access, &:merge) [imported_fields, raw_fields, custom_fields].reduce({}.with_indifferent_access, &:merge)

View file

@ -196,10 +196,10 @@ module Channel::Filter::IdentifySender
end end
def self.cleanup_email(string) def self.cleanup_email(string)
string = string.downcase string.downcase
string.strip! .strip
string.delete!('"') .delete('"')
string .sub(/\A'(.*)'\z/, '\1')
end end
end end

View file

@ -2648,6 +2648,42 @@ test('check getRecipientArticle format', function() {
verify = App.Utils.getRecipientArticle(ticket, article, agent, article.type, email_addresses, false) verify = App.Utils.getRecipientArticle(ticket, article, agent, article.type, email_addresses, false)
deepEqual(verify, result) deepEqual(verify, result)
customer = {
login: 'login',
firstname: 'firstname',
lastname: 'lastname',
email: "'customer@example.com'",
}
agent = {
login: 'login',
firstname: 'firstname',
lastname: 'lastname',
email: 'agent@example.com',
}
ticket = {
customer: customer,
}
article = {
message_id: 'message_id21',
created_by: agent,
type: {
name: 'email',
},
sender: {
name: 'Agent',
},
from: customer.email,
to: 'agent@example.com',
}
result = {
to: 'customer@example.com',
cc: '',
body: '',
in_reply_to: 'message_id21',
}
verify = App.Utils.getRecipientArticle(ticket, article, article.created_by, article.type)
deepEqual(verify, result)
}); });
test("contentTypeCleanup", function() { test("contentTypeCleanup", function() {

View file

@ -1,14 +1,16 @@
require 'rails_helper' require 'rails_helper'
RSpec.describe Channel::EmailParser, type: :model do RSpec.describe Channel::EmailParser, type: :model do
let(:ticket) { create(:ticket) }
let(:mail_file) { Rails.root.join('test', 'data', 'mail', 'mail001.box') } let(:mail_file) { Rails.root.join('test', 'data', 'mail', 'mail001.box') }
let(:raw_mail) { File.read(mail_file).sub(/(?<=^Subject: ).*$/, test_string) } let(:raw_mail) { File.read(mail_file) }
let(:test_string) do
Setting.get('ticket_hook') + Setting.get('ticket_hook_divider') + ticket.number
end
describe '#process' do describe '#process' do
let(:raw_mail) { File.read(mail_file).sub(/(?<=^Subject: ).*$/, test_string) }
let(:test_string) do
Setting.get('ticket_hook') + Setting.get('ticket_hook_divider') + ticket.number
end
let(:ticket) { create(:ticket) }
context 'when email subject contains ticket reference' do context 'when email subject contains ticket reference' do
it 'adds message to ticket' do it 'adds message to ticket' do
expect { described_class.new.process({}, raw_mail) } expect { described_class.new.process({}, raw_mail) }

View file

@ -3033,6 +3033,40 @@ Content-Type: text/html; charset=us-ascii; format=flowed
}, },
}, },
}, },
{
data: <<~RAW_MAIL.chomp,
From: me@example.com
To: Bob Smith <'customer_outlook_recipient_not_in_address_book@example.com'>
Subject: some subject for outlook recipient issue
Content-Type: text/html; charset=us-ascii;
test
RAW_MAIL
success: true,
result: {
0 => {
priority: '2 normal',
title: 'some subject for outlook recipient issue',
},
1 => {
content_type: 'text/html',
body: 'test',
sender: 'Customer',
type: 'email',
internal: false,
},
},
verify: {
users: [
{
firstname: 'Bob',
lastname: 'Smith',
fullname: 'Bob Smith',
email: 'customer_outlook_recipient_not_in_address_book@example.com',
},
],
},
},
{ {
data: File.read(Rails.root.join('test', 'data', 'mail', 'mail067.box')), data: File.read(Rails.root.join('test', 'data', 'mail', 'mail067.box')),
success: true, success: true,