Skip to content

Commit 707ba28

Browse files
authored
Watcher: Ensure mail message ids are unique per watch action (#30112)
Email message IDs are supposed to be unique. In order to guarantee this, we need to take the action id of a watch action into account as well, not just the watch id from the watch execution context. This prevents that two actions from the same watch execution end up with the same message id.
1 parent e1a16a6 commit 707ba28

File tree

4 files changed

+91
-3
lines changed

4 files changed

+91
-3
lines changed

x-pack/plugin/watcher/src/main/java/org/elasticsearch/xpack/watcher/actions/email/ExecutableEmailAction.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ public Action.Result execute(String actionId, WatchExecutionContext ctx, Payload
6363
}
6464

6565
Email.Builder email = action.getEmail().render(templateEngine, model, htmlSanitizer, attachments);
66-
email.id(ctx.id().value());
66+
email.id(actionId + "_" + ctx.id().value());
6767

6868
if (ctx.simulateAction(actionId)) {
6969
return new EmailAction.Result.Simulated(email.build());

x-pack/plugin/watcher/src/main/java/org/elasticsearch/xpack/watcher/notification/email/Email.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -354,7 +354,7 @@ public Builder attach(Attachment attachment) {
354354
* after this is called is incorrect.
355355
*/
356356
public Email build() {
357-
assert id != null : "email id should not be null (should be set to the watch id";
357+
assert id != null : "email id should not be null";
358358
Email email = new Email(id, from, replyTo, priority, sentDate, to, cc, bcc, subject, textBody, htmlBody,
359359
unmodifiableMap(attachments));
360360
attachments = null;

x-pack/plugin/watcher/src/test/java/org/elasticsearch/xpack/watcher/actions/email/EmailActionTests.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -171,7 +171,7 @@ public void testExecute() throws Exception {
171171
assertThat(result, instanceOf(EmailAction.Result.Success.class));
172172
assertThat(((EmailAction.Result.Success) result).account(), equalTo(account));
173173
Email actualEmail = ((EmailAction.Result.Success) result).email();
174-
assertThat(actualEmail.id(), is(wid.value()));
174+
assertThat(actualEmail.id(), is("_id_" + wid.value()));
175175
assertThat(actualEmail, notNullValue());
176176
assertThat(actualEmail.subject(), is(subject == null ? null : subject.getTemplate()));
177177
assertThat(actualEmail.textBody(), is(textBody == null ? null : textBody.getTemplate()));
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
/*
2+
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
3+
* or more contributor license agreements. Licensed under the Elastic License;
4+
* you may not use this file except in compliance with the Elastic License.
5+
*/
6+
package org.elasticsearch.xpack.watcher.actions.email;
7+
8+
import org.elasticsearch.common.settings.ClusterSettings;
9+
import org.elasticsearch.common.settings.Setting;
10+
import org.elasticsearch.common.settings.Settings;
11+
import org.elasticsearch.test.ESTestCase;
12+
import org.elasticsearch.xpack.core.watcher.execution.WatchExecutionContext;
13+
import org.elasticsearch.xpack.core.watcher.watch.Payload;
14+
import org.elasticsearch.xpack.watcher.common.text.TextTemplateEngine;
15+
import org.elasticsearch.xpack.watcher.notification.email.EmailService;
16+
import org.elasticsearch.xpack.watcher.notification.email.EmailTemplate;
17+
import org.elasticsearch.xpack.watcher.notification.email.HtmlSanitizer;
18+
import org.elasticsearch.xpack.watcher.notification.email.support.EmailServer;
19+
import org.elasticsearch.xpack.watcher.test.MockTextTemplateEngine;
20+
import org.elasticsearch.xpack.watcher.test.WatcherTestUtils;
21+
import org.junit.After;
22+
import org.junit.Before;
23+
24+
import javax.mail.internet.MimeMessage;
25+
import java.util.ArrayList;
26+
import java.util.Collections;
27+
import java.util.HashSet;
28+
import java.util.List;
29+
import java.util.Set;
30+
31+
import static org.hamcrest.Matchers.hasSize;
32+
33+
public class EmailMessageIdTests extends ESTestCase {
34+
35+
private EmailServer server;
36+
private TextTemplateEngine textTemplateEngine = new MockTextTemplateEngine();
37+
private HtmlSanitizer htmlSanitizer = new HtmlSanitizer(Settings.EMPTY);
38+
private EmailService emailService;
39+
private EmailAction emailAction;
40+
41+
@Before
42+
public void startSmtpServer() {
43+
server = EmailServer.localhost(logger);
44+
45+
Settings settings = Settings.builder()
46+
.put("xpack.notification.email.account.test.smtp.auth", true)
47+
.put("xpack.notification.email.account.test.smtp.user", EmailServer.USERNAME)
48+
.put("xpack.notification.email.account.test.smtp.password", EmailServer.PASSWORD)
49+
.put("xpack.notification.email.account.test.smtp.port", server.port())
50+
.put("xpack.notification.email.account.test.smtp.host", "localhost")
51+
.build();
52+
53+
Set<Setting<?>> registeredSettings = new HashSet<>(ClusterSettings.BUILT_IN_CLUSTER_SETTINGS);
54+
registeredSettings.addAll(EmailService.getSettings());
55+
ClusterSettings clusterSettings = new ClusterSettings(settings, registeredSettings);
56+
emailService = new EmailService(settings, null, clusterSettings);
57+
EmailTemplate emailTemplate = EmailTemplate.builder().from("from@example.org").to("to@example.org")
58+
.subject("subject").textBody("body").build();
59+
emailAction = new EmailAction(emailTemplate, null, null, null, null, null);
60+
}
61+
62+
@After
63+
public void stopSmtpServer() {
64+
server.stop();
65+
}
66+
67+
public void testThatMessageIdIsUnique() throws Exception {
68+
List<MimeMessage> messages = new ArrayList<>();
69+
server.addListener(messages::add);
70+
ExecutableEmailAction firstEmailAction = new ExecutableEmailAction(emailAction, logger, emailService, textTemplateEngine,
71+
htmlSanitizer, Collections.emptyMap());
72+
ExecutableEmailAction secondEmailAction = new ExecutableEmailAction(emailAction, logger, emailService, textTemplateEngine,
73+
htmlSanitizer, Collections.emptyMap());
74+
75+
WatchExecutionContext ctx = WatcherTestUtils.createWatchExecutionContext(logger);
76+
firstEmailAction.execute("my_first_action_id", ctx, Payload.EMPTY);
77+
secondEmailAction.execute("my_second_action_id", ctx, Payload.EMPTY);
78+
79+
assertThat(messages, hasSize(2));
80+
// check for unique message ids, should be two as well
81+
Set<String> messageIds = new HashSet<>();
82+
for (MimeMessage message : messages) {
83+
messageIds.add(message.getMessageID());
84+
}
85+
assertThat(messageIds, hasSize(2));
86+
}
87+
}
88+

0 commit comments

Comments
 (0)