Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement Reply-To header support when replying #8880

Merged
merged 1 commit into from
Feb 28, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 9 additions & 3 deletions lib/Model/IMAPMessage.php
Original file line number Diff line number Diff line change
Expand Up @@ -310,6 +310,7 @@ public function jsonSerialize() {
'messageId' => $this->getMessageId(),
'from' => $this->getFrom()->jsonSerialize(),
'to' => $this->getTo()->jsonSerialize(),
'replyTo' => $this->getReplyTo()->jsonSerialize(),
'cc' => $this->getCC()->jsonSerialize(),
'bcc' => $this->getBCC()->jsonSerialize(),
'subject' => $this->getSubject(),
Expand Down Expand Up @@ -426,17 +427,22 @@ public function setInReplyTo(string $id) {
throw new Exception('not implemented');
}

/**
* @return AddressList
*/
public function getReplyTo(): AddressList {
return $this->replyTo;
}

/**
* @param string $id
* @param AddressList $replyTo
*
* @throws Exception
*
* @return void
*/
public function setReplyTo(string $id) {
throw new Exception('not implemented');
public function setReplyTo(AddressList $replyTo) {
throw new Exception('IMAP message is immutable');
}

public function isEncrypted(): bool {
Expand Down
10 changes: 10 additions & 0 deletions lib/Model/IMessage.php
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,16 @@ public function getTo(): AddressList;
*/
public function setTo(AddressList $to);

/**
* @return AddressList
*/
public function getReplyTo(): AddressList;

/**
* @param AddressList $replyTo
*/
public function setReplyTo(AddressList $replyTo);

/**
* @return AddressList
*/
Expand Down
20 changes: 20 additions & 0 deletions lib/Model/Message.php
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,9 @@ class Message implements IMessage {
/** @var AddressList */
private $to;

/** @var AddressList */
private $replyTo;

/** @var AddressList */
private $cc;

Expand All @@ -63,6 +66,7 @@ class Message implements IMessage {
public function __construct() {
$this->from = new AddressList();
$this->to = new AddressList();
$this->replyTo = new AddressList();
$this->cc = new AddressList();
$this->bcc = new AddressList();
}
Expand Down Expand Up @@ -126,6 +130,22 @@ public function setTo(AddressList $to) {
$this->to = $to;
}

/**
* @return AddressList
*/
public function getReplyTo(): AddressList {
return $this->replyTo;
}

/**
* @param AddressList $replyTo
*
* @return void
*/
public function setReplyTo(AddressList $replyTo) {
$this->replyTo = $replyTo;
}

/**
* @return AddressList
*/
Expand Down
14 changes: 9 additions & 5 deletions src/ReplyBuilder.js
Original file line number Diff line number Diff line change
Expand Up @@ -73,11 +73,15 @@ const RecipientType = Object.seal({
Cc: 2,
})

export const buildRecipients = (envelope, ownAddress) => {
export const buildRecipients = (envelope, ownAddress, replyTo) => {
let recipientType = RecipientType.None
const isOwnAddress = (a) => a.email === ownAddress.email
const isNotOwnAddress = negate(isOwnAddress)

// The Reply-To header has higher precedence than the From header.
// This re-uses Horde's handling of the reply_to field directly.
const from = replyTo !== undefined ? replyTo : envelope.from

// Locate why we received this envelope
// Can be in 'to', 'cc' or unknown
let replyingAddress = envelope.to.find(isOwnAddress)
Expand All @@ -97,28 +101,28 @@ export const buildRecipients = (envelope, ownAddress) => {
if (recipientType === RecipientType.To) {
// Send to everyone except yourself, plus the original sender if not ourself
to = envelope.to.filter(isNotOwnAddress)
to = to.concat(envelope.from.filter(isNotOwnAddress))
to = to.concat(from.filter(isNotOwnAddress))

// CC remains the same
cc = envelope.cc
} else if (recipientType === RecipientType.Cc) {
// Send to the same people, plus the sender if not ourself
to = envelope.to.concat(envelope.from.filter(isNotOwnAddress))
to = envelope.to.concat(from.filter(isNotOwnAddress))

// All CC values are being kept except the replying address
cc = envelope.cc.filter(isNotOwnAddress)
} else {
// Send to the same recipient and the sender (if not ourself) -> answer all
to = envelope.to
to = to.concat(envelope.from.filter(isNotOwnAddress))
to = to.concat(from.filter(isNotOwnAddress))

// Keep CC values
cc = envelope.cc
}

// edge case: pure self-sent email
if (to.length === 0) {
to = envelope.from
to = from
}

return {
Expand Down
4 changes: 2 additions & 2 deletions src/store/actions.js
Original file line number Diff line number Diff line change
Expand Up @@ -400,7 +400,7 @@ export default {
commit('startComposerSession', {
data: {
accountId: reply.data.accountId,
to: reply.data.from,
to: original.replyTo !== undefined ? original.replyTo : reply.data.from,
cc: [],
subject: buildReplySubject(reply.data.subject),
body: data.body,
Expand All @@ -416,7 +416,7 @@ export default {
const recipients = buildReplyRecipients(reply.data, {
email: account.emailAddress,
label: account.name,
})
}, original.replyTo)
commit('startComposerSession', {
data: {
accountId: reply.data.accountId,
Expand Down
1 change: 1 addition & 0 deletions tests/Unit/Model/IMAPMessageTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,7 @@ public function testSerialize() {
'to' => [ [ 'label' => '[email protected]', 'email' => '[email protected]' ] ],
'cc' => [ [ 'label' => '[email protected]', 'email' => '[email protected]' ] ],
'bcc' => [ [ 'label' => '[email protected]', 'email' => '[email protected]' ] ],
'replyTo' => [ [ 'label' => '[email protected]', 'email' => '[email protected]' ] ],
'subject' => 'subject',
'dateInt' => 1451606400,
'flags' => [
Expand Down
Loading