Set Reply-To on outgoing email such that users reply to Gerrit directly
Change-Id: I4640a3342aa1b2b3014f9b61812e7d633e33d80c
This commit is contained in:
parent
d64dd9968c
commit
31d60f0ce4
@ -3534,7 +3534,6 @@ If the IMAP protocol is used for retrieving emails, IMAPv4 IDLE can be used to
|
|||||||
keep the connection with the email server alive and receive a push when a new
|
keep the connection with the email server alive and receive a push when a new
|
||||||
email is delivered to the inbox. In this case, Gerrit will process the email
|
email is delivered to the inbox. In this case, Gerrit will process the email
|
||||||
immediately and will not have a fetch delay.
|
immediately and will not have a fetch delay.
|
||||||
|
|
||||||
+
|
+
|
||||||
Defaults to false.
|
Defaults to false.
|
||||||
|
|
||||||
@ -3727,6 +3726,16 @@ should expire.
|
|||||||
+
|
+
|
||||||
By default, unset, so no Expiry-Date header is generated.
|
By default, unset, so no Expiry-Date header is generated.
|
||||||
|
|
||||||
|
[[sendemail.replyToAddress]]sendemail.replyToAddress::
|
||||||
|
+
|
||||||
|
A custom Reply-To address should only be provided if Gerrit is set up to
|
||||||
|
receive emails and the inbound address differs from
|
||||||
|
<<sendemail.from,sendemail.from>>.
|
||||||
|
It will be set as Reply-To header on all types of outgoing email where
|
||||||
|
Gerrit can parse back a user's reply.
|
||||||
|
+
|
||||||
|
Defaults to an empty string which adds <<sendemail.from,sendemail.from>> as
|
||||||
|
Reply-To if inbound email is enabled and the review's author otherwise.
|
||||||
|
|
||||||
[[site]]
|
[[site]]
|
||||||
=== Section site
|
=== Section site
|
||||||
|
@ -17,6 +17,7 @@ package com.google.gerrit.acceptance.server.mail;
|
|||||||
import com.google.common.collect.ImmutableList;
|
import com.google.common.collect.ImmutableList;
|
||||||
import com.google.gerrit.acceptance.AbstractDaemonTest;
|
import com.google.gerrit.acceptance.AbstractDaemonTest;
|
||||||
import com.google.gerrit.acceptance.PushOneCommit;
|
import com.google.gerrit.acceptance.PushOneCommit;
|
||||||
|
import com.google.gerrit.acceptance.TestAccount;
|
||||||
import com.google.gerrit.extensions.api.changes.ReviewInput;
|
import com.google.gerrit.extensions.api.changes.ReviewInput;
|
||||||
import com.google.gerrit.extensions.api.changes.ReviewInput.CommentInput;
|
import com.google.gerrit.extensions.api.changes.ReviewInput.CommentInput;
|
||||||
import com.google.gerrit.extensions.client.Comment;
|
import com.google.gerrit.extensions.client.Comment;
|
||||||
@ -40,6 +41,10 @@ public class AbstractMailIT extends AbstractDaemonTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected String createChangeWithReview() throws Exception {
|
protected String createChangeWithReview() throws Exception {
|
||||||
|
return createChangeWithReview(admin);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected String createChangeWithReview(TestAccount reviewer) throws Exception {
|
||||||
// Create change
|
// Create change
|
||||||
String file = "gerrit-server/test.txt";
|
String file = "gerrit-server/test.txt";
|
||||||
String contents = "contents \nlorem \nipsum \nlorem";
|
String contents = "contents \nlorem \nipsum \nlorem";
|
||||||
@ -49,6 +54,7 @@ public class AbstractMailIT extends AbstractDaemonTest {
|
|||||||
String changeId = r.getChangeId();
|
String changeId = r.getChangeId();
|
||||||
|
|
||||||
// Review it
|
// Review it
|
||||||
|
setApiUser(reviewer);
|
||||||
ReviewInput input = new ReviewInput();
|
ReviewInput input = new ReviewInput();
|
||||||
input.message = "I have two comments";
|
input.message = "I have two comments";
|
||||||
input.comments = new HashMap<>();
|
input.comments = new HashMap<>();
|
||||||
|
@ -0,0 +1,48 @@
|
|||||||
|
// Copyright (C) 2017 The Android Open Source Project
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package com.google.gerrit.acceptance.server.mail;
|
||||||
|
|
||||||
|
import static com.google.common.truth.Truth.assertThat;
|
||||||
|
|
||||||
|
import com.google.gerrit.acceptance.GerritConfig;
|
||||||
|
import com.google.gerrit.server.mail.send.EmailHeader;
|
||||||
|
import java.util.Map;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
public class MailSenderIT extends AbstractMailIT {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@GerritConfig(name = "sendemail.replyToAddress", value = "custom@gerritcodereview.com")
|
||||||
|
@GerritConfig(name = "receiveemail.protocol", value = "POP3")
|
||||||
|
public void outgoingMailHasCustomReplyToHeader() throws Exception {
|
||||||
|
createChangeWithReview(user);
|
||||||
|
// Check that the custom address was added as Reply-To
|
||||||
|
assertThat(sender.getMessages()).hasSize(1);
|
||||||
|
Map<String, EmailHeader> headers = sender.getMessages().iterator().next().headers();
|
||||||
|
assertThat(headers.get("Reply-To")).isInstanceOf(EmailHeader.String.class);
|
||||||
|
assertThat(((EmailHeader.String) headers.get("Reply-To")).getString())
|
||||||
|
.isEqualTo("custom@gerritcodereview.com");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void outgoingMailHasUserEmailInReplyToHeader() throws Exception {
|
||||||
|
createChangeWithReview(user);
|
||||||
|
// Check that the user's email was added as Reply-To
|
||||||
|
assertThat(sender.getMessages()).hasSize(1);
|
||||||
|
Map<String, EmailHeader> headers = sender.getMessages().iterator().next().headers();
|
||||||
|
assertThat(headers.get("Reply-To")).isInstanceOf(EmailHeader.String.class);
|
||||||
|
assertThat(((EmailHeader.String) headers.get("Reply-To")).getString()).contains(user.email);
|
||||||
|
}
|
||||||
|
}
|
@ -29,7 +29,9 @@ import com.google.gerrit.reviewdb.client.Project;
|
|||||||
import com.google.gerrit.reviewdb.client.RobotComment;
|
import com.google.gerrit.reviewdb.client.RobotComment;
|
||||||
import com.google.gerrit.server.CommentsUtil;
|
import com.google.gerrit.server.CommentsUtil;
|
||||||
import com.google.gerrit.server.account.WatchConfig.NotifyType;
|
import com.google.gerrit.server.account.WatchConfig.NotifyType;
|
||||||
|
import com.google.gerrit.server.config.GerritServerConfig;
|
||||||
import com.google.gerrit.server.mail.MailUtil;
|
import com.google.gerrit.server.mail.MailUtil;
|
||||||
|
import com.google.gerrit.server.mail.receive.Protocol;
|
||||||
import com.google.gerrit.server.patch.PatchFile;
|
import com.google.gerrit.server.patch.PatchFile;
|
||||||
import com.google.gerrit.server.patch.PatchList;
|
import com.google.gerrit.server.patch.PatchList;
|
||||||
import com.google.gerrit.server.patch.PatchListNotAvailableException;
|
import com.google.gerrit.server.patch.PatchListNotAvailableException;
|
||||||
@ -50,6 +52,7 @@ import java.util.List;
|
|||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
import org.eclipse.jgit.lib.Config;
|
||||||
import org.eclipse.jgit.lib.Repository;
|
import org.eclipse.jgit.lib.Repository;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
@ -104,16 +107,23 @@ public class CommentSender extends ReplyToChangeSender {
|
|||||||
private String patchSetComment;
|
private String patchSetComment;
|
||||||
private List<LabelVote> labels = Collections.emptyList();
|
private List<LabelVote> labels = Collections.emptyList();
|
||||||
private final CommentsUtil commentsUtil;
|
private final CommentsUtil commentsUtil;
|
||||||
|
private final boolean incomingEmailEnabled;
|
||||||
|
private final String replyToAddress;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
public CommentSender(
|
public CommentSender(
|
||||||
EmailArguments ea,
|
EmailArguments ea,
|
||||||
CommentsUtil commentsUtil,
|
CommentsUtil commentsUtil,
|
||||||
|
@GerritServerConfig Config cfg,
|
||||||
@Assisted Project.NameKey project,
|
@Assisted Project.NameKey project,
|
||||||
@Assisted Change.Id id)
|
@Assisted Change.Id id)
|
||||||
throws OrmException {
|
throws OrmException {
|
||||||
super(ea, "comment", newChangeData(ea, project, id));
|
super(ea, "comment", newChangeData(ea, project, id));
|
||||||
this.commentsUtil = commentsUtil;
|
this.commentsUtil = commentsUtil;
|
||||||
|
this.incomingEmailEnabled =
|
||||||
|
cfg.getEnum("receiveemail", null, "protocol", Protocol.NONE).ordinal()
|
||||||
|
> Protocol.NONE.ordinal();
|
||||||
|
this.replyToAddress = cfg.getString("sendemail", null, "replyToAddress");
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setComments(List<Comment> comments) throws OrmException {
|
public void setComments(List<Comment> comments) throws OrmException {
|
||||||
@ -151,6 +161,15 @@ public class CommentSender extends ReplyToChangeSender {
|
|||||||
// Add header that enables identifying comments on parsed email.
|
// Add header that enables identifying comments on parsed email.
|
||||||
// Grouping is currently done by timestamp.
|
// Grouping is currently done by timestamp.
|
||||||
setHeader("X-Gerrit-Comment-Date", timestamp);
|
setHeader("X-Gerrit-Comment-Date", timestamp);
|
||||||
|
|
||||||
|
if (incomingEmailEnabled) {
|
||||||
|
if (replyToAddress == null) {
|
||||||
|
// Remove Reply-To and use outbound SMTP (default) instead.
|
||||||
|
removeHeader("Reply-To");
|
||||||
|
} else {
|
||||||
|
setHeader("Reply-To", replyToAddress);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -319,6 +319,11 @@ public abstract class OutgoingEmail {
|
|||||||
headers.put(name, new EmailHeader.String(value));
|
headers.put(name, new EmailHeader.String(value));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Remove a header from the outgoing message. */
|
||||||
|
protected void removeHeader(final String name) {
|
||||||
|
headers.remove(name);
|
||||||
|
}
|
||||||
|
|
||||||
protected void setHeader(final String name, final Date date) {
|
protected void setHeader(final String name, final Date date) {
|
||||||
headers.put(name, new EmailHeader.Date(date));
|
headers.put(name, new EmailHeader.Date(date));
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user