Skip to content

Commit a5e437f

Browse files
artembilangaryrussell
authored andcommitted
INT-2543: Relax mail host when mail-props present
JIRA: https://jira.spring.io/browse/INT-2543 We may have a mail server host configured in the properties and the target session will resolve it properly from provided `javaMailProperties`. The same applies for `username` * Do not require `host` and `username`, when `javaMailProperties` is provided * Add additional factory methods into the `Mail` factory for Java DSL * Add Java DSL sample into the `mail.adoc`
1 parent 0ac7660 commit a5e437f

File tree

7 files changed

+155
-32
lines changed

7 files changed

+155
-32
lines changed

spring-integration-mail/src/main/java/org/springframework/integration/mail/config/MailOutboundChannelAdapterParser.java

Lines changed: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2011 the original author or authors.
2+
* Copyright 2002-2019 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -23,7 +23,6 @@
2323
import org.springframework.beans.factory.support.BeanDefinitionReaderUtils;
2424
import org.springframework.beans.factory.xml.ParserContext;
2525
import org.springframework.integration.config.xml.AbstractOutboundChannelAdapterParser;
26-
import org.springframework.integration.config.xml.IntegrationNamespaceUtils;
2726
import org.springframework.integration.mail.MailSendingMessageHandler;
2827
import org.springframework.mail.javamail.JavaMailSenderImpl;
2928
import org.springframework.util.Assert;
@@ -33,6 +32,7 @@
3332
* Parser for the <outbound-channel-adapter/> element of the 'mail' namespace.
3433
*
3534
* @author Mark Fisher
35+
* @author Artem Bilan
3636
*/
3737
public class MailOutboundChannelAdapterParser extends AbstractOutboundChannelAdapterParser {
3838

@@ -41,20 +41,28 @@ protected AbstractBeanDefinition parseConsumer(Element element, ParserContext pa
4141
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(MailSendingMessageHandler.class);
4242
String mailSenderRef = element.getAttribute("mail-sender");
4343
String host = element.getAttribute("host");
44+
boolean hasHost = StringUtils.hasText(host);
4445
String port = element.getAttribute("port");
4546
String username = element.getAttribute("username");
4647
String password = element.getAttribute("password");
48+
String javaMailProperties = element.getAttribute("java-mail-properties");
49+
boolean hasJavaMailProperties = StringUtils.hasText(javaMailProperties);
4750
if (StringUtils.hasText(mailSenderRef)) {
48-
Assert.isTrue(!StringUtils.hasText(host) && !StringUtils.hasText(username) && !StringUtils.hasText(password),
51+
Assert.isTrue(!hasHost
52+
&& !StringUtils.hasText(username)
53+
&& !StringUtils.hasText(password),
4954
"The 'host', 'username', and 'password' properties " +
50-
"should not be provided when using a 'mail-sender' reference.");
55+
"should not be provided when using a 'mail-sender' reference.");
5156
builder.addConstructorArgReference(mailSenderRef);
5257
}
5358
else {
54-
Assert.hasText(host, "Either a 'mail-sender' reference or 'host' property is required.");
59+
Assert.isTrue(!hasHost || !hasJavaMailProperties,
60+
"Either a 'mail-sender' or 'java-mail-properties' reference or 'host' property is required.");
5561
BeanDefinitionBuilder mailSenderBuilder =
5662
BeanDefinitionBuilder.genericBeanDefinition(JavaMailSenderImpl.class);
57-
mailSenderBuilder.addPropertyValue("host", host);
63+
if (hasHost) {
64+
mailSenderBuilder.addPropertyValue("host", host);
65+
}
5866
if (StringUtils.hasText(username)) {
5967
mailSenderBuilder.addPropertyValue("username", username);
6068
}
@@ -64,11 +72,13 @@ protected AbstractBeanDefinition parseConsumer(Element element, ParserContext pa
6472
if (StringUtils.hasText(port)) {
6573
mailSenderBuilder.addPropertyValue("port", port);
6674
}
67-
IntegrationNamespaceUtils.setReferenceIfAttributeDefined(
68-
mailSenderBuilder, element, "java-mail-properties", "javaMailProperties");
75+
if (hasJavaMailProperties) {
76+
mailSenderBuilder.addPropertyReference("javaMailProperties", javaMailProperties);
77+
}
6978

70-
String mailSenderBeanName = BeanDefinitionReaderUtils.registerWithGeneratedName(
71-
mailSenderBuilder.getBeanDefinition(), parserContext.getRegistry());
79+
String mailSenderBeanName =
80+
BeanDefinitionReaderUtils.registerWithGeneratedName(mailSenderBuilder.getBeanDefinition(),
81+
parserContext.getRegistry());
7282
builder.addConstructorArgReference(mailSenderBeanName);
7383
}
7484
return builder.getBeanDefinition();

spring-integration-mail/src/main/java/org/springframework/integration/mail/dsl/Mail.java

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2014-2016 the original author or authors.
2+
* Copyright 2014-2019 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -17,22 +17,53 @@
1717
package org.springframework.integration.mail.dsl;
1818

1919
import org.springframework.integration.mail.ImapMailReceiver;
20+
import org.springframework.integration.mail.MailSendingMessageHandler;
2021
import org.springframework.integration.mail.Pop3MailReceiver;
2122
import org.springframework.integration.mail.transformer.MailToStringTransformer;
23+
import org.springframework.lang.Nullable;
24+
import org.springframework.mail.MailSender;
2225

2326
/**
2427
* The factory for Spring Integration Mail components.
2528
*
2629
* @author Gary Russell
2730
* @author Artem Bilan
31+
*
2832
* @since 5.0
2933
*/
3034
public final class Mail {
3135

32-
public static MailSendingMessageHandlerSpec outboundAdapter(String host) {
36+
/**
37+
* A {@link MailSendingMessageHandlerSpec} factory.
38+
* Note: the Java Mail properties must be provided with the particular host.
39+
* @return the {@link MailSendingMessageHandlerSpec} instance.
40+
* @since 5.1.3
41+
* @see MailSendingMessageHandlerSpec#javaMailProperties
42+
*/
43+
public static MailSendingMessageHandlerSpec outboundAdapter() {
44+
return new MailSendingMessageHandlerSpec(null);
45+
}
46+
47+
/**
48+
* A {@link MailSendingMessageHandlerSpec} factory based on provide {@code host}.
49+
* @param host the mail host to connect to.
50+
* @return the {@link MailSendingMessageHandlerSpec} instance.
51+
*/
52+
public static MailSendingMessageHandlerSpec outboundAdapter(@Nullable String host) {
3353
return new MailSendingMessageHandlerSpec(host);
3454
}
3555

56+
/**
57+
* A convenient factory method to produce {@link MailSendingMessageHandler}
58+
* based on provided {@link MailSender}.
59+
* @param mailSender the {@link MailSender} to use mail sending operations.
60+
* @return the {@link MailSendingMessageHandler} instance.
61+
* @since 5.1.3
62+
*/
63+
public static MailSendingMessageHandler outboundAdapter(MailSender mailSender) {
64+
return new MailSendingMessageHandler(mailSender);
65+
}
66+
3667
/**
3768
* A {@link Pop3MailInboundChannelAdapterSpec} factory using a default
3869
* {@link Pop3MailReceiver}.

spring-integration-mail/src/main/java/org/springframework/integration/mail/dsl/MailSendingMessageHandlerSpec.java

Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2014-2016 the original author or authors.
2+
* Copyright 2014-2019 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -24,19 +24,21 @@
2424
import org.springframework.integration.dsl.MessageHandlerSpec;
2525
import org.springframework.integration.mail.MailSendingMessageHandler;
2626
import org.springframework.integration.support.PropertiesBuilder;
27+
import org.springframework.lang.Nullable;
2728
import org.springframework.mail.javamail.JavaMailSenderImpl;
2829

2930
/**
3031
* @author Gary Russell
3132
* @author Artem Bilan
33+
*
3234
* @since 5.0
3335
*/
3436
public class MailSendingMessageHandlerSpec
3537
extends MessageHandlerSpec<MailSendingMessageHandlerSpec, MailSendingMessageHandler> {
3638

3739
private final JavaMailSenderImpl sender = new JavaMailSenderImpl();
3840

39-
MailSendingMessageHandlerSpec(String host) {
41+
MailSendingMessageHandlerSpec(@Nullable String host) {
4042
this.sender.setHost(host);
4143
this.target = new MailSendingMessageHandler(this.sender);
4244
}
@@ -70,7 +72,7 @@ public MailSendingMessageHandlerSpec javaMailProperties(Consumer<PropertiesBuild
7072
* @return the spec.
7173
* @see JavaMailSenderImpl#setProtocol(String)
7274
*/
73-
public MailSendingMessageHandlerSpec protocol(String protocol) {
75+
public MailSendingMessageHandlerSpec protocol(@Nullable String protocol) {
7476
this.sender.setProtocol(protocol);
7577
return this;
7678
}
@@ -94,19 +96,33 @@ public MailSendingMessageHandlerSpec port(int port) {
9496
* @see JavaMailSenderImpl#setUsername(String)
9597
* @see JavaMailSenderImpl#setPassword(String)
9698
*/
97-
public MailSendingMessageHandlerSpec credentials(String username, String password) {
99+
public MailSendingMessageHandlerSpec credentials(@Nullable String username, @Nullable String password) {
98100
this.sender.setUsername(username);
99101
this.sender.setPassword(password);
100102
return this;
101103
}
102104

105+
/**
106+
* Set the mail user password.
107+
* A convenient method when {@code username} is provided in the Java mail properties.
108+
* @param password the password.
109+
* @return the spec.
110+
* @since 5.1.3
111+
* @see JavaMailSenderImpl#setPassword(String)
112+
* @see #javaMailProperties(Properties)
113+
*/
114+
public MailSendingMessageHandlerSpec password(@Nullable String password) {
115+
this.sender.setPassword(password);
116+
return this;
117+
}
118+
103119
/**
104120
* Set the default encoding.
105121
* @param defaultEncoding the default encoding.
106122
* @return the spec.
107123
* @see JavaMailSenderImpl#setDefaultEncoding(String)
108124
*/
109-
public MailSendingMessageHandlerSpec defaultEncoding(String defaultEncoding) {
125+
public MailSendingMessageHandlerSpec defaultEncoding(@Nullable String defaultEncoding) {
110126
this.sender.setDefaultEncoding(defaultEncoding);
111127
return this;
112128
}
@@ -117,7 +133,7 @@ public MailSendingMessageHandlerSpec defaultEncoding(String defaultEncoding) {
117133
* @return the spec.
118134
* @see JavaMailSenderImpl#setDefaultFileTypeMap(FileTypeMap)
119135
*/
120-
public MailSendingMessageHandlerSpec defaultFileTypeMap(FileTypeMap defaultFileTypeMap) {
136+
public MailSendingMessageHandlerSpec defaultFileTypeMap(@Nullable FileTypeMap defaultFileTypeMap) {
121137
this.sender.setDefaultFileTypeMap(defaultFileTypeMap);
122138
return this;
123139
}

spring-integration-mail/src/main/resources/org/springframework/integration/mail/config/spring-integration-mail-5.1.xsd

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,8 @@
2929
</xsd:documentation>
3030
</xsd:annotation>
3131
<xsd:choice minOccurs="0" maxOccurs="2">
32-
<xsd:element ref="integration:poller" minOccurs="0" maxOccurs="1"/>
33-
<xsd:element name="request-handler-advice-chain" type="integration:handlerAdviceChainType" minOccurs="0" maxOccurs="1" />
32+
<xsd:element ref="integration:poller" minOccurs="0"/>
33+
<xsd:element name="request-handler-advice-chain" type="integration:handlerAdviceChainType" minOccurs="0"/>
3434
</xsd:choice>
3535
<xsd:attributeGroup ref="integration:channelAdapterAttributes"/>
3636
<xsd:attribute name="mail-sender" type="xsd:string">

spring-integration-mail/src/test/java/org/springframework/integration/mail/config/MailOutboundChannelAdapterParserTests.java

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2016 the original author or authors.
2+
* Copyright 2002-2019 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -40,6 +40,7 @@
4040
* @author Mark Fisher
4141
* @author Gary Russell
4242
* @author Gunnar Hillert
43+
* @author Artem Bilan
4344
*/
4445
public class MailOutboundChannelAdapterParserTests {
4546

@@ -66,7 +67,7 @@ public void advised() {
6667
Object adapter = context.getBean("advised.adapter");
6768
MessageHandler handler = (MessageHandler)
6869
new DirectFieldAccessor(adapter).getPropertyValue("handler");
69-
handler.handleMessage(new GenericMessage<String>("foo"));
70+
handler.handleMessage(new GenericMessage<>("foo"));
7071
assertEquals(1, adviceCalled);
7172
context.close();
7273
}
@@ -105,7 +106,7 @@ public void adapterWithJavaMailProperties() {
105106
MailSender mailSender = (MailSender) fieldAccessor.getPropertyValue("mailSender");
106107
assertNotNull(mailSender);
107108
Properties javaMailProperties = (Properties) TestUtils.getPropertyValue(mailSender, "javaMailProperties");
108-
assertEquals(7, javaMailProperties.size());
109+
assertEquals(9, javaMailProperties.size());
109110
assertNotNull(javaMailProperties);
110111
assertEquals("true", javaMailProperties.get("mail.smtps.auth"));
111112
context.close();
@@ -114,10 +115,11 @@ public void adapterWithJavaMailProperties() {
114115
public static class FooAdvice extends AbstractRequestHandlerAdvice {
115116

116117
@Override
117-
protected Object doInvoke(ExecutionCallback callback, Object target, Message<?> message) throws Exception {
118+
protected Object doInvoke(ExecutionCallback callback, Object target, Message<?> message) {
118119
adviceCalled++;
119120
return null;
120121
}
121122

122123
}
124+
123125
}
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,16 @@
11
<?xml version="1.0" encoding="UTF-8"?>
22
<beans xmlns="http://www.springframework.org/schema/beans"
3-
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4-
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
3+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4+
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
55
http://www.springframework.org/schema/integration/mail http://www.springframework.org/schema/integration/mail/spring-integration-mail.xsd
66
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd"
7-
xmlns:int-mail="http://www.springframework.org/schema/integration/mail"
8-
xmlns:util="http://www.springframework.org/schema/util">
7+
xmlns:int-mail="http://www.springframework.org/schema/integration/mail"
8+
xmlns:util="http://www.springframework.org/schema/util">
99

1010
<int-mail:outbound-channel-adapter
11-
id="adapterWithHostProperty" host="somehost" username="someuser"
12-
password="somepassword" java-mail-properties="javaMailProperties"/>
11+
id="adapterWithHostProperty"
12+
password="somepassword"
13+
java-mail-properties="javaMailProperties"/>
1314

1415
<util:properties id="javaMailProperties">
1516
<prop key="mail.imap.socketFactory.class">javax.net.ssl.SSLSocketFactory</prop>
@@ -18,6 +19,8 @@
1819
<prop key="mail.transport.protocol">smtps</prop>
1920
<prop key="mail.smtps.auth">true</prop>
2021
<prop key="mail.smtp.starttls.enable">true</prop>
22+
<prop key="mail.smtp.host">somehost</prop>
23+
<prop key="mail.smtp.user">someuser</prop>
2124
<prop key="mail.debug">false</prop>
2225
</util:properties>
2326
</beans>

src/reference/asciidoc/mail.adoc

Lines changed: 63 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -232,6 +232,18 @@ Alternatively, you can provide the host, username, and password, as the followin
232232
----
233233
====
234234

235+
Starting with version 5.1.3, the `host`, `username` ane `mail-sender` can be omitted, if `java-mail-properties` is provided.
236+
However the `host` and `username` has to be configured with appropriate Java mail properties, e.g. for SMTP:
237+
238+
====
239+
[source]
240+
----
241+
242+
mail.smtp.host=smtp.gmail.com
243+
mail.smtp.port=587
244+
----
245+
====
246+
235247
NOTE: As with any outbound Channel Adapter, if the referenced channel is a `PollableChannel`, you should provide a `<poller>` element (see <<endpoint-namespace>>).
236248

237249
When you use the namespace support, you can also use a `header-enricher` message transformer.
@@ -322,8 +334,7 @@ By default, the `ImapMailReceiver` searches for messages based on the default `S
322334
* hHave not been processed by this mail receiver (enabled by the use of the custom USER flag or simply NOT FLAGGED if not supported)
323335

324336
The custom user flag is `spring-integration-mail-adapter`, but you can configure it.
325-
Since version 2.2, the `SearchTerm` used by the `ImapMailReceiver` is fully configurable with `SearchTermStrategy`,
326-
which you can inject by using the `search-term-strategy` attribute.
337+
Since version 2.2, the `SearchTerm` used by the `ImapMailReceiver` is fully configurable with `SearchTermStrategy`, which you can inject by using the `search-term-strategy` attribute.
327338
`SearchTermStrategy` is a strategy interface with a single method that lets you create an instance of the `SearchTerm` used by the `ImapMailReceiver`.
328339
The following listing shows the `SearchTermStrategy` interface:
329340

@@ -548,3 +559,53 @@ public class Mover {
548559
====
549560

550561
IMPORTANT: For the message to be still available for manipulation after the transaction, _should-delete-messages_ must be set to 'false'.
562+
563+
[[java-dsl-configuration]]
564+
=== Configuring channel adapters with the Java DSL
565+
566+
To configure mail mail component in Java DSL, the framework provides a `o.s.i.mail.dsl.Mail` factory, which can be used like this:
567+
568+
====
569+
[source, java]
570+
----
571+
@SpringBootApplication
572+
public class MailApplication {
573+
574+
public static void main(String[] args) {
575+
new SpringApplicationBuilder(MailApplication.class)
576+
.web(false)
577+
.run(args);
578+
}
579+
580+
@Bean
581+
public IntegrationFlow imapMailFlow() {
582+
return IntegrationFlows
583+
.from(Mail.imapInboundAdapter("imap://user:pw@host:port/INBOX")
584+
.searchTermStrategy(this::fromAndNotSeenTerm)
585+
.userFlag("testSIUserFlag")
586+
.simpleContent(true)
587+
.javaMailProperties(p -> p.put("mail.debug", "false")),
588+
e -> e.autoStartup(true)
589+
.poller(p -> p.fixedDelay(1000)))
590+
.channel(MessageChannels.queue("imapChannel"))
591+
.get();
592+
}
593+
594+
@Bean
595+
public IntegrationFlow sendMailFlow() {
596+
return IntegrationFlows.from("sendMailChannel")
597+
.enrichHeaders(Mail.headers()
598+
.subjectFunction(m -> "foo")
599+
.from("foo@bar")
600+
.toFunction(m -> new String[] { "bar@baz" }))
601+
.handle(Mail.outboundAdapter("gmail")
602+
.port(smtpServer.getPort())
603+
.credentials("user", "pw")
604+
.protocol("smtp")),
605+
e -> e.id("sendMailEndpoint"))
606+
.get();
607+
}
608+
}
609+
----
610+
====
611+

0 commit comments

Comments
 (0)