Skip to content

Commit

Permalink
Configure mail session properties (backport, fixes #542)
Browse files Browse the repository at this point in the history
Backport of #541
  • Loading branch information
marcelmay committed Feb 25, 2023
1 parent a2565b6 commit 4312c94
Show file tree
Hide file tree
Showing 5 changed files with 164 additions and 43 deletions.
9 changes: 9 additions & 0 deletions docs/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -1170,6 +1170,15 @@ <h4>How can I use nested test classes (with @Nested)?</h4>
}
}
}
</code></pre><!-- @formatter:on -->
<h4>How can I configure mail session properties?</h4>
<p>You can configure per protocol specific mail session properties:</p>
<pre><code class="language-java"><!-- @formatter:off -->
GreenMail greenMail = new GreenMail(new ServerSetup[]{
ServerSetupTest.SMTP,
ServerSetupTest.IMAP.mailSessionProperty("mail.imap.minidletime", "100")
});
Session session = greenMail.getImap().createSession(); // Will have configured property set
</code></pre><!-- @formatter:on -->
</section>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,22 +4,31 @@
*/
package com.icegreen.greenmail.server;

import java.io.IOException;
import java.net.*;
import java.util.*;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import javax.mail.NoSuchProviderException;
import javax.mail.Session;
import javax.mail.Store;

import com.icegreen.greenmail.Managers;
import com.icegreen.greenmail.util.DummySSLServerSocketFactory;
import com.icegreen.greenmail.util.ServerSetup;
import com.icegreen.greenmail.util.Service;
import javax.mail.NoSuchProviderException;
import javax.mail.Session;
import javax.mail.Store;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketException;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;

/**
* @author Wael Chatila
* @version $Id: $
Expand Down Expand Up @@ -82,7 +91,7 @@ protected ServerSocket openServerSocket() throws IOException {
}

// Port gets dynamically allocated if 0, so need to wait till after bind
setup = setup.withPort(socket.getLocalPort());
setup = setup.port(socket.getLocalPort());
setName(setup.getProtocol() + ':' + setup.getBindAddress() + ':' + setup.getPort());

return socket;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

import java.util.Objects;
import java.util.Properties;
import java.util.function.UnaryOperator;

/**
* Defines the default ports
Expand All @@ -18,6 +19,7 @@
* <tr><td>imaps</td><td>993</td></tr>
* </table>
* Use {@link ServerSetupTest} for non-default ports
* <p/>
*
* @author Wael Chatila
* @version $Id: $
Expand Down Expand Up @@ -85,6 +87,7 @@ public class ServerSetup {
* Timeout when GreenMail starts a server, in milliseconds.
*/
private long serverStartupTimeout = SERVER_STARTUP_TIMEOUT;
private final Properties mailSessionProperties = new Properties();

/**
* Creates a configuration.
Expand All @@ -104,8 +107,9 @@ public ServerSetup(int port, String bindAddress, String protocol) {
}

public static String getLocalHostAddress() {
// Always pretend that we are 127.0.0.1. Doesn't matter what we return here and we have no way of guessing the
// "correct" address anyways if we have multiple external interfaces.
// Always pretend that we are 127.0.0.1.
// Doesn't matter what we return here, and we have no way of guessing the
// "correct" address anyway if we have multiple external interfaces.
// InetAddress.getLocalHost().getHostAddress() is unreliable.
return "127.0.0.1";
}
Expand Down Expand Up @@ -168,8 +172,20 @@ public long getServerStartupTimeout() {
*
* @param port the port (0 for dynamic port allocation).
* @return a modified copy.
* @deprecated use {@link #port(int)} - will be deprecated in 2.1
*/
@Deprecated()
public ServerSetup withPort(int port) {
return port(port);
}

/**
* Creates a deep copy and updates port.
*
* @param port the port (0 for dynamic port allocation).
* @return a modified copy.
*/
public ServerSetup port(int port) {
return createCopy(port, getBindAddress(), getProtocol());
}

Expand Down Expand Up @@ -203,6 +219,16 @@ public ServerSetup setVerbose(boolean verbose) {
return this;
}

/**
* Creates a deep copy with verbose configured.
*
* @param verbose if true enables JavaMail debug output by setting JavaMail property 'mail.debug'
* @return a deep copy with verbose configured
*/
public ServerSetup verbose(boolean verbose) {
return createCopy().setVerbose(verbose);
}

/**
* Sets the server startup timeout in milliseconds.
*
Expand All @@ -214,8 +240,19 @@ public void setServerStartupTimeout(long timeoutInMs) {

/**
* Creates default properties for a JavaMail session.
* <p/>
* Concrete server implementations can add protocol specific settings.
* <p/>
* Order of application:
* <ol>
* <li>Default GreenMail properties - e.g. common properties such as
* <code>mail.debug</code> when log level is debug or protocol specific settings
* such as <code>mail.smtp.port</code></li>
* <li>ServerSetup configured mail session properties</li>
* <li>Parameter provided properties</li>
* </ol>
* Note: Be careful to not override essential GreenMail provided properties, e.g. <code>mail.PROTOCOL.port</code>
* <p/>
* For details see
* <ul>
* <li>https://jakarta.ee/specifications/mail/2.0/apidocs/jakarta.mail/module-summary.html for some general settings</li>
Expand Down Expand Up @@ -271,6 +308,11 @@ public Properties configureJavaMailSessionProperties(Properties properties, bool
// Auto configure stores.
props.setProperty("mail.store.protocol", getProtocol());

// Merge with default properties
if (!mailSessionProperties.isEmpty()) {
props.putAll(mailSessionProperties);
}

// Merge with optional additional properties
if (null != properties && !properties.isEmpty()) {
props.putAll(properties);
Expand All @@ -283,28 +325,21 @@ public Properties configureJavaMailSessionProperties(Properties properties, bool
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof ServerSetup)) return false;

ServerSetup that = (ServerSetup) o;

if (port != that.port) return false;
if (readTimeout != that.readTimeout) return false;
if (connectionTimeout != that.connectionTimeout) return false;
if (writeTimeout != that.writeTimeout) return false;
if (serverStartupTimeout != that.serverStartupTimeout) return false;
if (!Objects.equals(bindAddress, that.bindAddress)) return false;
return Objects.equals(protocol, that.protocol);
return port == that.port &&
readTimeout == that.readTimeout &&
connectionTimeout == that.connectionTimeout &&
writeTimeout == that.writeTimeout &&
verbose == that.verbose &&
serverStartupTimeout == that.serverStartupTimeout &&
bindAddress.equals(that.bindAddress) &&
protocol.equals(that.protocol) &&
mailSessionProperties.equals(that.mailSessionProperties);
}

@Override
public int hashCode() {
int result = port;
result = 31 * result + (bindAddress != null ? bindAddress.hashCode() : 0);
result = 31 * result + (protocol != null ? protocol.hashCode() : 0);
result = 31 * result + (int) (readTimeout ^ (readTimeout >>> 32));
result = 31 * result + (int) (connectionTimeout ^ (connectionTimeout >>> 32));
result = 31 * result + (int) (writeTimeout ^ (writeTimeout >>> 32));
result = 31 * result + (int) (serverStartupTimeout ^ (serverStartupTimeout >>> 32));
return result;
return Objects.hash(port, bindAddress, protocol, readTimeout, connectionTimeout, writeTimeout, verbose, serverStartupTimeout, mailSessionProperties);
}

@Override
Expand All @@ -316,8 +351,9 @@ public String toString() {
", readTimeout=" + readTimeout +
", connectionTimeout=" + connectionTimeout +
", writeTimeout=" + writeTimeout +
", verbose=" + verbose +
", serverStartupTimeout=" + serverStartupTimeout +
", verbose=" + isVerbose() +
", mailProperties=" + mailSessionProperties +
'}';
}

Expand Down Expand Up @@ -356,35 +392,79 @@ public ServerSetup createCopy(int port, String bindAddress, String protocol) {
setup.setReadTimeout(getReadTimeout());
setup.setWriteTimeout(getWriteTimeout());
setup.setVerbose(isVerbose());
setup.mailSessionProperties.putAll(mailSessionProperties);

return setup;
}

/**
* Creates a copy with verbose mode enabled.
* Create a new server setup copy, configured with given JavaMail session property.
* <p>
* For protocol specific properties see
* <ul>
* <li>https://jakarta.ee/specifications/mail/2.0/apidocs/jakarta.mail/jakarta/mail/package-summary.html for general settings</li>
* <li>https://jakarta.ee/specifications/mail/1.6/apidocs/index.html?com/sun/mail/smtp/package-summary.html for SMTP properties.</li>
* <li>https://jakarta.ee/specifications/mail/1.6/apidocs/index.html?com/sun/mail/imap/package-summary.html for IMAP properties</li>
* <li>https://jakarta.ee/specifications/mail/1.6/apidocs/index.html?com/sun/mail/pop3/package-summary.html for POP3 properties.</li>
* </ul
*
* @param serverSetups the server setups.
* @return copies of server setups with verbose mode enabled.
* @param key the key
* @param value the value
* @return a deep copy with configured session property
*/
public static ServerSetup[] verbose(ServerSetup[] serverSetups) {
public ServerSetup mailSessionProperty(String key, String value) {
ServerSetup updatedServerSetup = createCopy();
updatedServerSetup.mailSessionProperties.put(key, value);
return updatedServerSetup;
}

/**
* Creates a copy applying given mutator on each copy.
*
* @param serverSetups the server setups
* @param copyMutator the mutator receiving the original server setup and returning a modified copy
* @return mutated copies
*/
public static ServerSetup[] createCopy(ServerSetup[] serverSetups,
UnaryOperator<ServerSetup> copyMutator) {
ServerSetup[] copies = new ServerSetup[serverSetups.length];
for (int i = 0; i < serverSetups.length; i++) {
copies[i] = serverSetups[i].createCopy().setVerbose(true);
copies[i] = copyMutator.apply(serverSetups[i]);
}
return copies;
}

/**
* Creates a copy with verbose mode enabled.
*
* @param serverSetups the server setups.
* @return copies of server setups with verbose mode enabled.
*/
public static ServerSetup[] verbose(ServerSetup[] serverSetups) {
return createCopy(serverSetups, serverSetup -> serverSetup.verbose(true));
}

/**
* Creates a copy with dynamic ports (auto-detecting available ports) enabled.
*
* @param serverSetups the server setups.
* @return copies of server setups with verbose mode enabled.
*/
public static ServerSetup[] dynamicPort(ServerSetup[] serverSetups) {
ServerSetup[] copies = new ServerSetup[serverSetups.length];
for (int i = 0; i < serverSetups.length; i++) {
copies[i] = serverSetups[i].createCopy().dynamicPort();
}
return copies;
return createCopy(serverSetups, ServerSetup::dynamicPort);
}

/**
* Creates a copy with configured default mail session property.
* @see #mailSessionProperty(String, String)
*
* @param serverSetups the server setups.
* @param key the key
* @param value the value
* @return copies of server setups with verbose mode enabled.
*/
public static ServerSetup[] mailSessionProperty(ServerSetup[] serverSetups,
String key, String value) {
return createCopy(serverSetups, serverSetup -> serverSetup.mailSessionProperty(key, value));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package com.icegreen.greenmail.server;

import com.icegreen.greenmail.util.GreenMail;
import com.icegreen.greenmail.util.ServerSetup;
import com.icegreen.greenmail.util.ServerSetupTest;
import org.junit.Test;

import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.entry;

/**
* Base GreenMail test (no pre-configured GreenMail server)
*/
public class GreenMailBaseTest {
@Test
public void testCustomMailSessionProperties() {
GreenMail greenMail = new GreenMail(new ServerSetup[]{
ServerSetupTest.SMTP,
ServerSetupTest.IMAP.mailSessionProperty("a.key","a.value")});
assertThat(greenMail.getImap().createSession().getProperties()).contains(entry("a.key","a.value"));
assertThat(greenMail.getSmtp().createSession().getProperties()).doesNotContain(entry("a.key","a.value"));
}
}
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
package com.icegreen.greenmail.util;

import java.util.Properties;

import org.junit.Test;

import java.util.Properties;

import static org.assertj.core.api.Assertions.assertThat;


Expand Down Expand Up @@ -37,8 +37,8 @@ public void testCreate() {
properties.setProperty("greenmail.setup.test.smtp", "");
properties.setProperty(PropertiesBasedServerSetupBuilder.GREENMAIL_VERBOSE, "");
setups = setupBuilder.build(properties);
assertThat(setups).isEqualTo(new ServerSetup[]{ServerSetupTest.SMTP});
assertThat(setups[0].isVerbose()).isTrue();
assertThat(setups).isEqualTo(new ServerSetup[]{ServerSetupTest.SMTP.verbose(true)});

// With hostname
properties.clear();
Expand Down

0 comments on commit 4312c94

Please sign in to comment.