From 67cad60f2fa09252ba95276db922568f4c799ece Mon Sep 17 00:00:00 2001 From: bbottema Date: Tue, 14 Jun 2016 20:17:14 +0200 Subject: [PATCH] started renaming packages for #39 to match the domain name --- .../simplejavamail/MailException.java | 66 +- .../simplejavamail/Mailer.java | 1400 ++++++++--------- .../simplejavamail/ProxyConfig.java | 9 +- .../simplejavamail/ServerConfig.java | 2 +- .../simplejavamail/TransportStrategy.java | 478 +++--- .../email/AttachmentResource.java | 2 +- .../simplejavamail/email/Email.java | 4 +- .../simplejavamail/email/EmailException.java | 4 +- .../simplejavamail/email/EqualsHelper.java | 2 +- .../simplejavamail/email/Recipient.java | 2 +- .../simplejavamail/internal/Util.java | 2 +- .../socks/AuthenticatingSocks5Bridge.java | 8 +- .../internal/socks/common/Socks5Bridge.java | 11 +- .../internal/socks/common/SocksException.java | 2 +- .../socks/socks5client/KeyStoreInfo.java | 4 +- .../socks/socks5client/ProxyCredentials.java | 4 +- .../socks/socks5client/SSLConfiguration.java | 6 +- .../socks/socks5client/SSLSocks5.java | 2 +- .../internal/socks/socks5client/Socks5.java | 2 +- .../SocksAuthenticationHelper.java | 6 +- .../socks5client/SocksCommandSender.java | 6 +- .../socks/socks5client/SocksSocket.java | 6 +- .../socks/socks5server/AddressType.java | 2 +- .../socks5server/AnonymousSocks5Server.java | 6 +- .../socks/socks5server/Socks5Handler.java | 18 +- .../SocksServerReplyException.java | 6 +- .../socks/socks5server/SocksSession.java | 2 +- .../socks/socks5server/StreamUtil.java | 2 +- .../socks/socks5server/io/SocketPipe.java | 2 +- .../socks/socks5server/io/StreamPipe.java | 2 +- .../socks5server/msg/CommandMessage.java | 10 +- .../msg/CommandResponseMessage.java | 5 +- .../msg/MethodSelectionMessage.java | 4 +- .../socks/socks5server/msg/ServerReply.java | 2 +- .../util/MimeMessageParser.java | 2 +- src/test/java/demo/MailTestApp.java | 8 +- .../simplejavamail/MailerTest.java | 6 +- .../simplejavamail/email/EmailTest.java | 4 +- 38 files changed, 1057 insertions(+), 1052 deletions(-) rename src/main/java/org/{codemonkey => }/simplejavamail/MailException.java (95%) rename src/main/java/org/{codemonkey => }/simplejavamail/Mailer.java (96%) rename src/main/java/org/{codemonkey => }/simplejavamail/ProxyConfig.java (93%) rename src/main/java/org/{codemonkey => }/simplejavamail/ServerConfig.java (96%) rename src/main/java/org/{codemonkey => }/simplejavamail/TransportStrategy.java (95%) rename src/main/java/org/{codemonkey => }/simplejavamail/email/AttachmentResource.java (97%) rename src/main/java/org/{codemonkey => }/simplejavamail/email/Email.java (99%) rename src/main/java/org/{codemonkey => }/simplejavamail/email/EmailException.java (84%) rename src/main/java/org/{codemonkey => }/simplejavamail/email/EqualsHelper.java (98%) rename src/main/java/org/{codemonkey => }/simplejavamail/email/Recipient.java (96%) rename src/main/java/org/{codemonkey => }/simplejavamail/internal/Util.java (92%) rename src/main/java/org/{codemonkey => }/simplejavamail/internal/socks/AuthenticatingSocks5Bridge.java (93%) rename src/main/java/org/{codemonkey => }/simplejavamail/internal/socks/common/Socks5Bridge.java (64%) rename src/main/java/org/{codemonkey => }/simplejavamail/internal/socks/common/SocksException.java (92%) rename src/main/java/org/{codemonkey => }/simplejavamail/internal/socks/socks5client/KeyStoreInfo.java (88%) rename src/main/java/org/{codemonkey => }/simplejavamail/internal/socks/socks5client/ProxyCredentials.java (78%) rename src/main/java/org/{codemonkey => }/simplejavamail/internal/socks/socks5client/SSLConfiguration.java (92%) rename src/main/java/org/{codemonkey => }/simplejavamail/internal/socks/socks5client/SSLSocks5.java (95%) rename src/main/java/org/{codemonkey => }/simplejavamail/internal/socks/socks5client/Socks5.java (98%) rename src/main/java/org/{codemonkey => }/simplejavamail/internal/socks/socks5client/SocksAuthenticationHelper.java (95%) rename src/main/java/org/{codemonkey => }/simplejavamail/internal/socks/socks5client/SocksCommandSender.java (96%) rename src/main/java/org/{codemonkey => }/simplejavamail/internal/socks/socks5client/SocksSocket.java (97%) rename src/main/java/org/{codemonkey => }/simplejavamail/internal/socks/socks5server/AddressType.java (78%) rename src/main/java/org/{codemonkey => }/simplejavamail/internal/socks/socks5server/AnonymousSocks5Server.java (89%) rename src/main/java/org/{codemonkey => }/simplejavamail/internal/socks/socks5server/Socks5Handler.java (87%) rename src/main/java/org/{codemonkey => }/simplejavamail/internal/socks/socks5server/SocksServerReplyException.java (58%) rename src/main/java/org/{codemonkey => }/simplejavamail/internal/socks/socks5server/SocksSession.java (96%) rename src/main/java/org/{codemonkey => }/simplejavamail/internal/socks/socks5server/StreamUtil.java (74%) rename src/main/java/org/{codemonkey => }/simplejavamail/internal/socks/socks5server/io/SocketPipe.java (96%) rename src/main/java/org/{codemonkey => }/simplejavamail/internal/socks/socks5server/io/StreamPipe.java (97%) rename src/main/java/org/{codemonkey => }/simplejavamail/internal/socks/socks5server/msg/CommandMessage.java (86%) rename src/main/java/org/{codemonkey => }/simplejavamail/internal/socks/socks5server/msg/CommandResponseMessage.java (88%) rename src/main/java/org/{codemonkey => }/simplejavamail/internal/socks/socks5server/msg/MethodSelectionMessage.java (78%) rename src/main/java/org/{codemonkey => }/simplejavamail/internal/socks/socks5server/msg/ServerReply.java (91%) rename src/main/java/org/{codemonkey => }/simplejavamail/util/MimeMessageParser.java (99%) rename src/test/java/org/{codemonkey => }/simplejavamail/MailerTest.java (92%) rename src/test/java/org/{codemonkey => }/simplejavamail/email/EmailTest.java (97%) diff --git a/src/main/java/org/codemonkey/simplejavamail/MailException.java b/src/main/java/org/simplejavamail/MailException.java similarity index 95% rename from src/main/java/org/codemonkey/simplejavamail/MailException.java rename to src/main/java/org/simplejavamail/MailException.java index eb3fa04fd..eb664992a 100644 --- a/src/main/java/org/codemonkey/simplejavamail/MailException.java +++ b/src/main/java/org/simplejavamail/MailException.java @@ -1,34 +1,34 @@ -package org.codemonkey.simplejavamail; - -/** - * This exception is used to communicate errors during the sending of email. - * - * @author Benny Bottema - */ -@SuppressWarnings("serial") -public class MailException extends RuntimeException { - - static final String GENERIC_ERROR = "Third party error"; - static final String MISSING_HOST = "Can't send an email without host"; - static final String MISSING_USERNAME = "Can't have a password without username"; - static final String INVALID_ENCODING = "Encoding not accepted"; - static final String INVALID_RECIPIENT = "Invalid TO address: %s"; - static final String INVALID_REPLYTO = "Invalid REPLY TO address: %s"; - static final String INVALID_SENDER = "Invalid FROM address: %s"; - static final String MISSING_SENDER = "Email is not valid: missing sender"; - static final String MISSING_RECIPIENT = "Email is not valid: missing recipients"; - static final String MISSING_SUBJECT = "Email is not valid: missing subject"; - static final String MISSING_CONTENT = "Email is not valid: missing content body"; - static final String INVALID_DOMAINKEY = "Error signing MimeMessage with DKIM: %s"; - static final String INVALID_PROXY_SLL_COMBINATION = "Proxy is not supported for SSL connections (this is a limitation by the underlying JavaMail framework)"; - static final String MISSING_PROXY_USERNAME = "Missing proxy username"; - static final String MISSING_PROXY_PASSWORD = "Missing proxy password"; - - MailException(final String message) { - super(message); - } - - public MailException(final String message, final Exception cause) { - super(message, cause); - } +package org.simplejavamail; + +/** + * This exception is used to communicate errors during the sending of email. + * + * @author Benny Bottema + */ +@SuppressWarnings("serial") +public class MailException extends RuntimeException { + + static final String GENERIC_ERROR = "Third party error"; + static final String MISSING_HOST = "Can't send an email without host"; + static final String MISSING_USERNAME = "Can't have a password without username"; + static final String INVALID_ENCODING = "Encoding not accepted"; + static final String INVALID_RECIPIENT = "Invalid TO address: %s"; + static final String INVALID_REPLYTO = "Invalid REPLY TO address: %s"; + static final String INVALID_SENDER = "Invalid FROM address: %s"; + static final String MISSING_SENDER = "Email is not valid: missing sender"; + static final String MISSING_RECIPIENT = "Email is not valid: missing recipients"; + static final String MISSING_SUBJECT = "Email is not valid: missing subject"; + static final String MISSING_CONTENT = "Email is not valid: missing content body"; + static final String INVALID_DOMAINKEY = "Error signing MimeMessage with DKIM: %s"; + static final String INVALID_PROXY_SLL_COMBINATION = "Proxy is not supported for SSL connections (this is a limitation by the underlying JavaMail framework)"; + static final String MISSING_PROXY_USERNAME = "Missing proxy username"; + static final String MISSING_PROXY_PASSWORD = "Missing proxy password"; + + MailException(final String message) { + super(message); + } + + public MailException(final String message, final Exception cause) { + super(message, cause); + } } \ No newline at end of file diff --git a/src/main/java/org/codemonkey/simplejavamail/Mailer.java b/src/main/java/org/simplejavamail/Mailer.java similarity index 96% rename from src/main/java/org/codemonkey/simplejavamail/Mailer.java rename to src/main/java/org/simplejavamail/Mailer.java index 8b315d758..399ca5883 100644 --- a/src/main/java/org/codemonkey/simplejavamail/Mailer.java +++ b/src/main/java/org/simplejavamail/Mailer.java @@ -1,700 +1,700 @@ -package org.codemonkey.simplejavamail; - -import net.markenwerk.utils.mail.dkim.Canonicalization; -import net.markenwerk.utils.mail.dkim.DkimMessage; -import net.markenwerk.utils.mail.dkim.DkimSigner; -import net.markenwerk.utils.mail.dkim.SigningAlgorithm; -import org.codemonkey.simplejavamail.email.AttachmentResource; -import org.codemonkey.simplejavamail.email.Email; -import org.codemonkey.simplejavamail.email.Recipient; -import org.codemonkey.simplejavamail.internal.socks.AuthenticatingSocks5Bridge; -import org.codemonkey.simplejavamail.internal.socks.socks5server.AnonymousSocks5Server; -import org.hazlewood.connor.bottema.emailaddress.EmailAddressCriteria; -import org.hazlewood.connor.bottema.emailaddress.EmailAddressValidator; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import javax.activation.DataHandler; -import javax.activation.DataSource; -import javax.mail.*; -import javax.mail.internet.*; -import java.io.IOException; -import java.io.UnsupportedEncodingException; -import java.nio.charset.StandardCharsets; -import java.security.NoSuchAlgorithmException; -import java.security.spec.InvalidKeySpecException; -import java.util.Date; -import java.util.EnumSet; -import java.util.Map; -import java.util.Properties; - -import static java.lang.String.format; -import static org.codemonkey.simplejavamail.TransportStrategy.findStrategyForSession; -import static org.hazlewood.connor.bottema.emailaddress.EmailAddressCriteria.RFC_COMPLIANT; - -/** - * Mailing tool aimed for simplicity, for sending e-mails of any complexity. This includes e-mails with plain text and/or html content, - * embedded images and separate attachments, SMTP, SMTPS / SSL and SMTP + SSL, custom Session object, DKIM domain signing and even - * authenticated SOCKS proxy support. - *

- * This mailing tool abstracts the javax.mail API to a higher level easy to use API. This tool works with {@link Email} instances but can - * also convert traditional {@link MimeMessage} objects to and from {@link Email} object. - *

- * The e-mail message structure is built to work with all e-mail clients and has been tested with many different webclients as well as some - * desktop applications. - *

- * Technically, the resulting email structure is as follows:
- *

- *

- * - root
- * 	- related
- * 		- alternative
- * 			- mail text
- * 			- mail html text
- * 		- embedded images
- * 	- attachments
- * 
- *

- *
Usage example:
- *

- *

- * Email email = new Email();
- * email.setFromAddress("lollypop", "lolly.pop@somemail.com");
- * email.addRecipient("Sugar Cane", "sugar.cane@candystore.org", RecipientType.TO);
- * email.setText("We should meet up!!");
- * email.setTextHTML("<b>We should meet up!</b>");
- * email.setSubject("Hey");
- * new Mailer(preconfiguredMailSession).sendMail(email);
- * // or:
- * new Mailer("smtp.someserver.com", 25, "username", "password").sendMail(email);
- * 
- *

- * simplejavamail.org - * - * @author Benny Bottema - * @see Mailer.MimeEmailMessageWrapper - * @see Email - */ -@SuppressWarnings("WeakerAccess") -public class Mailer { - - private static final Logger LOGGER = LoggerFactory.getLogger(Mailer.class); - - /** - * Encoding used for setting body text, email address, headers, reply-to fields etc. ({@link StandardCharsets#UTF_8}). - */ - private static final String CHARACTER_ENCODING = StandardCharsets.UTF_8.name(); - - /** - * Used to actually send the email. This session can come from being passed in the default constructor, or made by Mailer - * directly, when no Session instance was provided. - * - * @see #Mailer(Session) - * @see #Mailer(String, Integer, String, String, TransportStrategy) - */ - private final Session session; - - /** - * The transport protocol strategy enum that actually handles the session configuration. Session configuration meaning setting the right - * properties for the appropriate transport type (ie. "mail.smtp.host" for SMTP, "mail.smtps.host" for SMTPS). - */ - private TransportStrategy transportStrategy; - - /** - * Intermediary SOCKS5 relay server that acts as bridge between JavaMail and remote proxy (since JavaMail only supports anonymous SOCKS - * proxies). Only set when {@link ProxyConfig} is provided. - */ - private AnonymousSocks5Server proxyServer = null; - - /** - * Email address restriction flags set to {@link EmailAddressCriteria#RFC_COMPLIANT} or overridden by by user with {@link - * #setEmailAddressCriteria(EnumSet)}. - */ - private EnumSet emailAddressCriteria = RFC_COMPLIANT; - - /** - * Custom Session constructor, stores the given mail session for later use. Assumes that *all* properties used to make a connection are - * configured (host, port, authentication and transport protocol settings). - * - * @param session A preconfigured mail {@link Session} object with which a {@link Message} can be produced. - */ - public Mailer(final Session session) { - this(session, ProxyConfig.SKIP_PROXY_CONFIG); - } - - /** - * Custom Session constructor with proxy, stores the given mail session for later use. Assumes that *all* properties used to make a - * connection are configured (host, port, authentication and transport protocol settings). - *

- * Only proxy settings are always added if details are provided. - * - * @param session A preconfigured mail {@link Session} object with which a {@link Message} can be produced. - * @param proxyConfig Remote proxy server details, if the connection should be run through a SOCKS proxy. - */ - @SuppressWarnings("SameParameterValue") - public Mailer(final Session session, ProxyConfig proxyConfig) { - this.session = session; - configureSessionWithProxy(proxyConfig, session.getProperties(), findStrategyForSession(session)); - } - - /** - * Common case constructor which produces a new {@link Session} on the fly, using default vanilla SMTP transport protocol. - * - * @param host The address URL of the SMTP server to be used. - * @param port The port of the SMTP server. - * @param username An optional username, may be null. - * @param password An optional password, may be null, but only if username is null as well. - * @see #Mailer(ServerConfig, TransportStrategy, ProxyConfig) - */ - public Mailer(final String host, final Integer port, final String username, final String password) { - this(new ServerConfig(host, port, username, password), TransportStrategy.SMTP_PLAIN, ProxyConfig.SKIP_PROXY_CONFIG); - } - - /** - * Common case constructor which produces a new {@link Session} on the fly, using default vanilla SMTP transport protocol. - * - * @param serverConfig Remote SMTP server details. - * @see #Mailer(ServerConfig, TransportStrategy, ProxyConfig) - */ - public Mailer(ServerConfig serverConfig) { - this(serverConfig, TransportStrategy.SMTP_PLAIN, ProxyConfig.SKIP_PROXY_CONFIG); - } - - /** - * Common case constructor which produces a new {@link Session} on the fly. Use this if you don't have a mail session configured in your - * web container, or Spring context etc. - * - * @param host The address URL of the SMTP server to be used. - * @param port The port of the SMTP server. - * @param username An optional username, may be null. - * @param password An optional password, may be null, but only if username is null as well. - * @param transportStrategy The transport protocol configuration type for handling SSL or TLS (or vanilla SMTP) - * @see #Mailer(ServerConfig, TransportStrategy, ProxyConfig) - */ - public Mailer(final String host, final Integer port, final String username, final String password, - final TransportStrategy transportStrategy) { - this(new ServerConfig(host, port, username, password), transportStrategy, ProxyConfig.SKIP_PROXY_CONFIG); - } - - /** - * Produces a new {@link Session} on the fly. Use this if you don't have a mail session configured in your web container, or Spring - * context etc. - * - * @param serverConfig Remote SMTP server details. - * @param transportStrategy The transport protocol configuration type for handling SSL or TLS (or vanilla SMTP) - * @see #Mailer(ServerConfig, TransportStrategy, ProxyConfig) - */ - public Mailer(ServerConfig serverConfig, final TransportStrategy transportStrategy) { - this(serverConfig, transportStrategy, ProxyConfig.SKIP_PROXY_CONFIG); - } - - /** - * Produces a new {@link Session} on the fly, using default vanilla SMTP transport protocol. Use this if you don't have a mail session - * configured in your web container, or Spring context etc. - * - * @param serverConfig Remote SMTP server details. - * @param proxyConfig Remote proxy server details, if the connection should be run through a SOCKS proxy. - * @see #Mailer(ServerConfig, TransportStrategy, ProxyConfig) - */ - public Mailer(ServerConfig serverConfig, final ProxyConfig proxyConfig) { - this(serverConfig, TransportStrategy.SMTP_PLAIN, proxyConfig); - } - - /** - * Main constructor which produces a new {@link Session} on the fly. Use this if you don't have a mail session configured in your web - * container, or Spring context etc. - * - * @param serverConfig Remote SMTP server details. - * @param transportStrategy The transport protocol configuration type for handling SSL or TLS (or vanilla SMTP) - * @param proxyConfig Remote proxy server details, if the connection should be run through a SOCKS proxy. - */ - public Mailer(ServerConfig serverConfig, final TransportStrategy transportStrategy, ProxyConfig proxyConfig) { - this.transportStrategy = transportStrategy; - this.session = createMailSession(serverConfig, proxyConfig); - this.emailAddressCriteria = null; - } - - /** - * Actually instantiates and configures the {@link Session} instance. Delegates resolving transport protocol specific properties to the - * {@link #transportStrategy} in two ways:

  1. request an initial property list which the strategy may pre-populate
  2. by - * requesting the property names according to the respective transport protocol it handles (for the host property for example it would - * be "mail.smtp.host" for SMTP and "mail.smtps.host" for SMTPS)
- *

- * Furthermore adds proxy SOCKS properties if a proxy configuration was provided, overwriting any SOCKS properties already present. - * - * @param serverConfig Remote SMTP server details. - * @param proxyConfig Remote proxy server details, if the connection should be run through a SOCKS proxy. - * @return A fully configured Session instance complete with transport protocol settings. - * @see TransportStrategy#generateProperties() - * @see TransportStrategy#propertyNameHost() - * @see TransportStrategy#propertyNamePort() - * @see TransportStrategy#propertyNameUsername() - * @see TransportStrategy#propertyNameAuthenticate() - * @see #configureSessionWithProxy(ProxyConfig, Properties, TransportStrategy) - */ - @SuppressWarnings("WeakerAccess") - protected Session createMailSession(final ServerConfig serverConfig, final ProxyConfig proxyConfig) { - if (transportStrategy == null) { - LOGGER.warn("Transport Strategy not set, using plain SMTP strategy instead."); - transportStrategy = TransportStrategy.SMTP_PLAIN; - } - Properties props = transportStrategy.generateProperties(); - props.put(transportStrategy.propertyNameHost(), serverConfig.getHost()); - //noinspection StatementWithEmptyBody - if (serverConfig.getPort() != null) { - props.put(transportStrategy.propertyNamePort(), String.valueOf(serverConfig.getPort())); - } else { - // let JavaMail's Transport objects determine default port base don the used protocol - } - - if (serverConfig.getUsername() != null) { - props.put(transportStrategy.propertyNameUsername(), serverConfig.getUsername()); - } - - configureSessionWithProxy(proxyConfig, props, transportStrategy); - - if (serverConfig.getPassword() != null) { - props.put(transportStrategy.propertyNameAuthenticate(), "true"); - return Session.getInstance(props, new Authenticator() { - @Override - protected PasswordAuthentication getPasswordAuthentication() { - return new PasswordAuthentication(serverConfig.getUsername(), serverConfig.getPassword()); - } - }); - } else { - return Session.getInstance(props); - } - } - - /** - * If a {@link ProxyConfig} was provided with a host address, then the appropriate properties are set, overriding any SOCKS properties - * already there. - *

- * These properties are "mail.smtp.socks.host" and "mail.smtp.socks.port", which are set to "localhost" and {@link - * ProxyConfig#getProxyBridgePort()}. - * - * @param proxyConfig Proxy server details, optionally with username / password. - * @param sessionProperties The properties to add the new configuration to. - * @param transportStrategy Used to verify if the current combination with proxy is allowed (SMTP with SSL trategy doesn't support any - * proxy, virtue of the underlying JavaMail framework). - */ - private void configureSessionWithProxy(ProxyConfig proxyConfig, Properties sessionProperties, TransportStrategy transportStrategy) { - if (!proxyConfig.requiresProxy()) { - LOGGER.debug("No proxy set, skipping proxy."); - } else { - if (transportStrategy == TransportStrategy.SMTP_SSL) { - throw new MailException(MailException.INVALID_PROXY_SLL_COMBINATION); - } - sessionProperties.put("mail.smtp.socks.host", proxyConfig.getRemoteProxyHost()); - sessionProperties.put("mail.smtp.socks.port", proxyConfig.getRemoteProxyPort()); - if (proxyConfig.requiresAuthentication()) { - sessionProperties.put("mail.smtp.socks.host", "localhost"); - sessionProperties.put("mail.smtp.socks.port", proxyConfig.getProxyBridgePort()); - proxyServer = new AnonymousSocks5Server(new AuthenticatingSocks5Bridge(proxyConfig), proxyConfig.getProxyBridgePort()); - } - } - } - - /** - * In case Simple Java Mail falls short somehow, you can get a hold of the internal {@link Session} instance to debug or tweak. Please - * let us know why you are needing this on https://github.com/bbottema/simple-java-mail/issues. - */ - public Session getSession() { - LOGGER.warn("Providing access to Session instance for emergency fall-back scenario. Please let us know why you need it."); - LOGGER.warn("\t>https://github.com/bbottema/simple-java-mail/issues"); - return session; - } - - /** - * Actually sets {@link Session#setDebug(boolean)} so that it generates debug information. To get more information out of the underlying - * JavaMail framework or out of Simple Java Mail, increase logging config of your chosen logging framework (examples here). - * - * @param debug Flag to indicate debug mode yes/no. - */ - public void setDebug(final boolean debug) { - session.setDebug(debug); - } - - /** - * Copies all property entries into the {@link Session} using {@link Session#getProperties()}. - * - * @param properties The source properties to add or override in the internal {@link Session} instance. - */ - public void applyProperties(final Properties properties) { - session.getProperties().putAll(properties); - } - - /** - * Processes an {@link Email} instance into a completely configured {@link Message}. - *

- * Sends the Sun JavaMail {@link Message} object using {@link Session#getTransport()}. It will call {@link Transport#connect()} assuming - * all connection details have been configured in the provided {@link Session} instance. - *

- * Performs a call to {@link Message#saveChanges()} as the Sun JavaMail API indicates it is needed to configure the message headers and - * providing a message id. - * - * @param email The information for the email to be sent. - * @throws MailException Can be thrown if an email isn't validating correctly, or some other problem occurs during connection, sending - * etc. - * @see #validate(Email) - * @see #produceMimeMessage(Email, Session) - * @see #setRecipients(Email, Message) - * @see #setTexts(Email, MimeMultipart) - * @see #setEmbeddedImages(Email, MimeMultipart) - * @see #setAttachments(Email, MimeMultipart) - */ - public final void sendMail(final Email email) - throws MailException { - if (validate(email)) { - boolean async = false; - if (async) { - new Thread() { - @Override - public void run() { - sendMailClosure(email); - } - }.start(); - } else { - sendMailClosure(email); - } - } - } - - private void sendMailClosure(Email email) { - try { - // fill and send wrapped mime message parts - MimeMessage message = produceMimeMessage(email, session); - if (email.isApplyDKIMSignature()) { - message = signMessageWithDKIM(message, email); - } - logSession(session, transportStrategy); - message.saveChanges(); // some headers and id's will be set for this specific message - Transport transport = session.getTransport(); - - try { - if (proxyServer != null) { - proxyServer.start(); - } - try { - transport.connect(); - transport.sendMessage(message, message.getAllRecipients()); - } finally { - //noinspection ThrowFromFinallyBlock - transport.close(); - } - } finally { - if (proxyServer != null) { - proxyServer.stop(); - } - } - } catch (final UnsupportedEncodingException e) { - throw new MailException(MailException.INVALID_ENCODING, e); - } catch (final MessagingException e) { - throw new MailException(MailException.GENERIC_ERROR, e); - } - } - - /** - * Simply logs host details, credentials used and whether authentication will take place and finally the transport protocol used. - */ - private void logSession(Session session, TransportStrategy transportStrategy) { - Properties properties = session.getProperties(); - final String specifics; - if (transportStrategy != null) { - final String logmsg = "starting mail session (host: %s, port: %s, username: %s, authenticate: %s, transport: %s)"; - specifics = format(logmsg, properties.get(transportStrategy.propertyNameHost()), - properties.get(transportStrategy.propertyNamePort()), properties.get(transportStrategy.propertyNameUsername()), - properties.get(transportStrategy.propertyNameAuthenticate()), transportStrategy); - } else { - specifics = properties.toString(); - } - LOGGER.debug(specifics); - } - - /** - * Validates an {@link Email} instance. Validation fails if the subject is missing, content is missing, or no recipients are defined. - * - * @param email The email that needs to be configured correctly. - * @return Always true (throws a {@link MailException} exception if validation fails). - * @throws MailException Is being thrown in any of the above causes. - * @see EmailAddressValidator - */ - @SuppressWarnings({ "SameReturnValue", "WeakerAccess" }) - public boolean validate(final Email email) - throws MailException { - if (email.getText() == null && email.getTextHTML() == null) { - throw new MailException(MailException.MISSING_CONTENT); - } else if (email.getSubject() == null || email.getSubject().equals("")) { - throw new MailException(MailException.MISSING_SUBJECT); - } else if (email.getRecipients().size() == 0) { - throw new MailException(MailException.MISSING_RECIPIENT); - } else if (email.getFromRecipient() == null) { - throw new MailException(MailException.MISSING_SENDER); - } else if (emailAddressCriteria != null) { - if (!EmailAddressValidator.isValid(email.getFromRecipient().getAddress(), emailAddressCriteria)) { - throw new MailException(format(MailException.INVALID_SENDER, email)); - } - for (final Recipient recipient : email.getRecipients()) { - if (!EmailAddressValidator.isValid(recipient.getAddress(), emailAddressCriteria)) { - throw new MailException(format(MailException.INVALID_RECIPIENT, email)); - } - } - if (email.getReplyToRecipient() != null && !EmailAddressValidator - .isValid(email.getReplyToRecipient().getAddress(), emailAddressCriteria)) { - throw new MailException(format(MailException.INVALID_REPLYTO, email)); - } - } - return true; - } - - /** - * Creates a new {@link MimeMessage} instance and prepares it in the email structure, so that it can be filled and send. - *

- * Fills subject, from,reply-to, content, sent-date, recipients, texts, embedded images, attachments, content and adds all headers. - * - * @param email The email message from which the subject and From-address are extracted. - * @param session The Session to attach the MimeMessage to - * @return A fully preparated {@link Message} instance, ready to be sent. - * @throws MessagingException May be thrown when the message couldn't be processed by JavaMail. - * @throws UnsupportedEncodingException Zie {@link InternetAddress#InternetAddress(String, String)}. - */ - public static MimeMessage produceMimeMessage(final Email email, final Session session) - throws MessagingException, UnsupportedEncodingException { - if (email == null) { - throw new IllegalStateException("email is missing"); - } - if (session == null) { - throw new IllegalStateException("session is needed, it cannot be attached later"); - } - // create new wrapper for each mail being sent (enable sending multiple emails with one mailer) - final MimeEmailMessageWrapper messageRoot = new MimeEmailMessageWrapper(); - final MimeMessage message = new MimeMessage(session); - // set basic email properties - message.setSubject(email.getSubject(), CHARACTER_ENCODING); - message.setFrom(new InternetAddress(email.getFromRecipient().getAddress(), email.getFromRecipient().getName(), CHARACTER_ENCODING)); - setReplyTo(email, message); - setRecipients(email, message); - // fill multipart structure - setTexts(email, messageRoot.multipartAlternativeMessages); - setEmbeddedImages(email, messageRoot.multipartRelated); - setAttachments(email, messageRoot.multipartRoot); - message.setContent(messageRoot.multipartRoot); - setHeaders(email, message); - message.setSentDate(new Date()); - return message; - } - - /** - * Fills the {@link Message} instance with recipients from the {@link Email}. - * - * @param email The message in which the recipients are defined. - * @param message The javax message that needs to be filled with recipients. - * @throws UnsupportedEncodingException See {@link InternetAddress#InternetAddress(String, String)}. - * @throws MessagingException See {@link Message#addRecipient(javax.mail.Message.RecipientType, Address)} - */ - private static void setRecipients(final Email email, final Message message) - throws UnsupportedEncodingException, MessagingException { - for (final Recipient recipient : email.getRecipients()) { - final Address address = new InternetAddress(recipient.getAddress(), recipient.getName(), CHARACTER_ENCODING); - message.addRecipient(recipient.getType(), address); - } - } - - /** - * Fills the {@link Message} instance with reply-to address. - * - * @param email The message in which the recipients are defined. - * @param message The javax message that needs to be filled with reply-to address. - * @throws UnsupportedEncodingException See {@link InternetAddress#InternetAddress(String, String)}. - * @throws MessagingException See {@link Message#setReplyTo(Address[])} - */ - private static void setReplyTo(final Email email, final Message message) - throws UnsupportedEncodingException, MessagingException { - final Recipient replyToRecipient = email.getReplyToRecipient(); - if (replyToRecipient != null) { - InternetAddress replyToAddress = new InternetAddress(replyToRecipient.getAddress(), replyToRecipient.getName(), - CHARACTER_ENCODING); - message.setReplyTo(new Address[] { replyToAddress }); - } - } - - /** - * Fills the {@link Message} instance with the content bodies (text and html). - * - * @param email The message in which the content is defined. - * @param multipartAlternativeMessages See {@link MimeMultipart#addBodyPart(BodyPart)} - * @throws MessagingException See {@link BodyPart#setText(String)}, {@link BodyPart#setContent(Object, String)} and {@link - * MimeMultipart#addBodyPart(BodyPart)}. - */ - private static void setTexts(final Email email, final MimeMultipart multipartAlternativeMessages) - throws MessagingException { - if (email.getText() != null) { - final MimeBodyPart messagePart = new MimeBodyPart(); - messagePart.setText(email.getText(), CHARACTER_ENCODING); - multipartAlternativeMessages.addBodyPart(messagePart); - } - if (email.getTextHTML() != null) { - final MimeBodyPart messagePartHTML = new MimeBodyPart(); - messagePartHTML.setContent(email.getTextHTML(), "text/html; charset=\"" + CHARACTER_ENCODING + "\""); - multipartAlternativeMessages.addBodyPart(messagePartHTML); - } - } - - /** - * Fills the {@link Message} instance with the embedded images from the {@link Email}. - * - * @param email The message in which the embedded images are defined. - * @param multipartRelated The branch in the email structure in which we'll stuff the embedded images. - * @throws MessagingException See {@link MimeMultipart#addBodyPart(BodyPart)} and {@link #getBodyPartFromDatasource(AttachmentResource, - * String)} - */ - private static void setEmbeddedImages(final Email email, final MimeMultipart multipartRelated) - throws MessagingException { - for (final AttachmentResource embeddedImage : email.getEmbeddedImages()) { - multipartRelated.addBodyPart(getBodyPartFromDatasource(embeddedImage, Part.INLINE)); - } - } - - /** - * Fills the {@link Message} instance with the attachments from the {@link Email}. - * - * @param email The message in which the attachments are defined. - * @param multipartRoot The branch in the email structure in which we'll stuff the attachments. - * @throws MessagingException See {@link MimeMultipart#addBodyPart(BodyPart)} and {@link #getBodyPartFromDatasource(AttachmentResource, - * String)} - */ - private static void setAttachments(final Email email, final MimeMultipart multipartRoot) - throws MessagingException { - for (final AttachmentResource resource : email.getAttachments()) { - multipartRoot.addBodyPart(getBodyPartFromDatasource(resource, Part.ATTACHMENT)); - } - } - - /** - * Sets all headers on the {@link Message} instance. Since we're not using a high-level JavaMail method, the JavaMail library says we - * need to do some encoding and 'folding' manually, to get the value right for the headers (see {@link MimeUtility}. - * - * @param email The message in which the headers are defined. - * @param message The {@link Message} on which to set the raw, encoded and folded headers. - * @throws UnsupportedEncodingException See {@link MimeUtility#encodeText(String, String, String)} - * @throws MessagingException See {@link Message#addHeader(String, String)} - * @see MimeUtility#encodeText(String, String, String) - * @see MimeUtility#fold(int, String) - */ - private static void setHeaders(final Email email, final Message message) - throws UnsupportedEncodingException, MessagingException { - // add headers (for raw message headers we need to 'fold' them using MimeUtility - for (Map.Entry header : email.getHeaders().entrySet()) { - String headerName = header.getKey(); - String headerValue = MimeUtility.encodeText(header.getValue(), CHARACTER_ENCODING, null); - String foldedHeaderValue = MimeUtility.fold(headerName.length() + 2, headerValue); - message.addHeader(header.getKey(), foldedHeaderValue); - } - } - - /** - * Helper method which generates a {@link BodyPart} from an {@link AttachmentResource} (from its {@link DataSource}) and a disposition - * type ({@link Part#INLINE} or {@link Part#ATTACHMENT}). With this the attachment data can be converted into objects that fit in the - * email structure.

For every attachment and embedded image a header needs to be set. - * - * @param attachmentResource An object that describes the attachment and contains the actual content data. - * @param dispositionType The type of attachment, {@link Part#INLINE} or {@link Part#ATTACHMENT} . - * @return An object with the attachment data read for placement in the email structure. - * @throws MessagingException All BodyPart setters. - */ - private static BodyPart getBodyPartFromDatasource(final AttachmentResource attachmentResource, final String dispositionType) - throws MessagingException { - final BodyPart attachmentPart = new MimeBodyPart(); - final DataSource dataSource = attachmentResource.getDataSource(); - // setting headers isn't working nicely using the javax mail API, so let's do that manually - String resourceName = attachmentResource.getName(); - final boolean dataSourceNameProvided = dataSource.getName() != null && !dataSource.getName().isEmpty(); - String fileName = dataSourceNameProvided ? dataSource.getName() : resourceName; - attachmentPart.setDataHandler(new DataHandler(attachmentResource.getDataSource())); - attachmentPart.setFileName(fileName); - attachmentPart.setHeader("Content-Type", dataSource.getContentType() + "; filename=" + fileName + "; name=" + fileName); - attachmentPart.setHeader("Content-ID", format("<%s>", resourceName)); - attachmentPart.setDisposition(dispositionType + "; size=0"); - return attachmentPart; - } - - /** - * Primes the {@link MimeMessage} instance for signing with DKIM. The signing itself is performed by {@link DkimMessage} and {@link - * DkimSigner} during the physical sending of the message. - * - * @param message The message to be signed when sent. - * @param email The {@link Email} that contains the relevant signing information - * @return The original mime message wrapped in a new one that performs signing when sent. - */ - static MimeMessage signMessageWithDKIM(MimeMessage message, Email email) { - try { - final DkimSigner dkimSigner = new DkimSigner(email.getSigningDomain(), email.getSelector(), - email.getDkimPrivateKeyInputStream()); - dkimSigner.setIdentity(email.getFromRecipient().getAddress()); - dkimSigner.setHeaderCanonicalization(Canonicalization.SIMPLE); - dkimSigner.setBodyCanonicalization(Canonicalization.RELAXED); - dkimSigner.setSigningAlgorithm(SigningAlgorithm.SHA256_WITH_RSA); - dkimSigner.setLengthParam(true); - dkimSigner.setZParam(false); - return new DkimMessage(message, dkimSigner); - } catch (IOException | NoSuchAlgorithmException | InvalidKeySpecException | MessagingException e) { - throw new MailException(format(MailException.INVALID_DOMAINKEY, e.getMessage()), e); - } - } - - /** - * This class conveniently wraps all necessary mimemessage parts that need to be filled with content, attachments etc. The root is - * ultimately sent using JavaMail.

The constructor creates a new email message constructed from {@link MimeMultipart} as - * follows: - *

- *

-	 * - root
-	 * 	- related
-	 * 		- alternative
-	 * 			- mail tekst
-	 * 			- mail html tekst
-	 * 		- embedded images
-	 * 	- attachments
-	 * 
- * - * @author Benny Bottema - */ - private static class MimeEmailMessageWrapper { - - private final MimeMultipart multipartRoot; - - private final MimeMultipart multipartRelated; - - private final MimeMultipart multipartAlternativeMessages; - - /** - * Creates an email skeleton structure, so that embedded images, attachments and (html) texts are being processed properly. - */ - MimeEmailMessageWrapper() { - multipartRoot = new MimeMultipart("mixed"); - final MimeBodyPart contentRelated = new MimeBodyPart(); - multipartRelated = new MimeMultipart("related"); - final MimeBodyPart contentAlternativeMessages = new MimeBodyPart(); - multipartAlternativeMessages = new MimeMultipart("alternative"); - try { - // construct mail structure - multipartRoot.addBodyPart(contentRelated); - contentRelated.setContent(multipartRelated); - multipartRelated.addBodyPart(contentAlternativeMessages); - contentAlternativeMessages.setContent(multipartAlternativeMessages); - } catch (final MessagingException e) { - throw new MailException(e.getMessage(), e); - } - } - - } - - /** - * Overrides the default email address validation restrictions {@link #emailAddressCriteria} when validating and sending emails using - * the current Mailer instance. - */ - public void setEmailAddressCriteria(EnumSet emailAddressCriteria) { - this.emailAddressCriteria = emailAddressCriteria; - } -} +package org.simplejavamail; + +import net.markenwerk.utils.mail.dkim.Canonicalization; +import net.markenwerk.utils.mail.dkim.DkimMessage; +import net.markenwerk.utils.mail.dkim.DkimSigner; +import net.markenwerk.utils.mail.dkim.SigningAlgorithm; +import org.simplejavamail.email.AttachmentResource; +import org.simplejavamail.email.Email; +import org.simplejavamail.email.Recipient; +import org.simplejavamail.internal.socks.AuthenticatingSocks5Bridge; +import org.simplejavamail.internal.socks.socks5server.AnonymousSocks5Server; +import org.hazlewood.connor.bottema.emailaddress.EmailAddressCriteria; +import org.hazlewood.connor.bottema.emailaddress.EmailAddressValidator; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.activation.DataHandler; +import javax.activation.DataSource; +import javax.mail.*; +import javax.mail.internet.*; +import java.io.IOException; +import java.io.UnsupportedEncodingException; +import java.nio.charset.StandardCharsets; +import java.security.NoSuchAlgorithmException; +import java.security.spec.InvalidKeySpecException; +import java.util.Date; +import java.util.EnumSet; +import java.util.Map; +import java.util.Properties; + +import static java.lang.String.format; +import static org.simplejavamail.TransportStrategy.findStrategyForSession; +import static org.hazlewood.connor.bottema.emailaddress.EmailAddressCriteria.RFC_COMPLIANT; + +/** + * Mailing tool aimed for simplicity, for sending e-mails of any complexity. This includes e-mails with plain text and/or html content, + * embedded images and separate attachments, SMTP, SMTPS / SSL and SMTP + SSL, custom Session object, DKIM domain signing and even + * authenticated SOCKS proxy support. + *

+ * This mailing tool abstracts the javax.mail API to a higher level easy to use API. This tool works with {@link Email} instances but can + * also convert traditional {@link MimeMessage} objects to and from {@link Email} object. + *

+ * The e-mail message structure is built to work with all e-mail clients and has been tested with many different webclients as well as some + * desktop applications. + *

+ * Technically, the resulting email structure is as follows:
+ *

+ *

+ * - root
+ * 	- related
+ * 		- alternative
+ * 			- mail text
+ * 			- mail html text
+ * 		- embedded images
+ * 	- attachments
+ * 
+ *

+ *
Usage example:
+ *

+ *

+ * Email email = new Email();
+ * email.setFromAddress("lollypop", "lolly.pop@somemail.com");
+ * email.addRecipient("Sugar Cane", "sugar.cane@candystore.org", RecipientType.TO);
+ * email.setText("We should meet up!!");
+ * email.setTextHTML("<b>We should meet up!</b>");
+ * email.setSubject("Hey");
+ * new Mailer(preconfiguredMailSession).sendMail(email);
+ * // or:
+ * new Mailer("smtp.someserver.com", 25, "username", "password").sendMail(email);
+ * 
+ *

+ * simplejavamail.org + * + * @author Benny Bottema + * @see Mailer.MimeEmailMessageWrapper + * @see Email + */ +@SuppressWarnings("WeakerAccess") +public class Mailer { + + private static final Logger LOGGER = LoggerFactory.getLogger(Mailer.class); + + /** + * Encoding used for setting body text, email address, headers, reply-to fields etc. ({@link StandardCharsets#UTF_8}). + */ + private static final String CHARACTER_ENCODING = StandardCharsets.UTF_8.name(); + + /** + * Used to actually send the email. This session can come from being passed in the default constructor, or made by Mailer + * directly, when no Session instance was provided. + * + * @see #Mailer(Session) + * @see #Mailer(String, Integer, String, String, TransportStrategy) + */ + private final Session session; + + /** + * The transport protocol strategy enum that actually handles the session configuration. Session configuration meaning setting the right + * properties for the appropriate transport type (ie. "mail.smtp.host" for SMTP, "mail.smtps.host" for SMTPS). + */ + private TransportStrategy transportStrategy; + + /** + * Intermediary SOCKS5 relay server that acts as bridge between JavaMail and remote proxy (since JavaMail only supports anonymous SOCKS + * proxies). Only set when {@link ProxyConfig} is provided. + */ + private AnonymousSocks5Server proxyServer = null; + + /** + * Email address restriction flags set to {@link EmailAddressCriteria#RFC_COMPLIANT} or overridden by by user with {@link + * #setEmailAddressCriteria(EnumSet)}. + */ + private EnumSet emailAddressCriteria = RFC_COMPLIANT; + + /** + * Custom Session constructor, stores the given mail session for later use. Assumes that *all* properties used to make a connection are + * configured (host, port, authentication and transport protocol settings). + * + * @param session A preconfigured mail {@link Session} object with which a {@link Message} can be produced. + */ + public Mailer(final Session session) { + this(session, ProxyConfig.SKIP_PROXY_CONFIG); + } + + /** + * Custom Session constructor with proxy, stores the given mail session for later use. Assumes that *all* properties used to make a + * connection are configured (host, port, authentication and transport protocol settings). + *

+ * Only proxy settings are always added if details are provided. + * + * @param session A preconfigured mail {@link Session} object with which a {@link Message} can be produced. + * @param proxyConfig Remote proxy server details, if the connection should be run through a SOCKS proxy. + */ + @SuppressWarnings("SameParameterValue") + public Mailer(final Session session, ProxyConfig proxyConfig) { + this.session = session; + configureSessionWithProxy(proxyConfig, session.getProperties(), findStrategyForSession(session)); + } + + /** + * Common case constructor which produces a new {@link Session} on the fly, using default vanilla SMTP transport protocol. + * + * @param host The address URL of the SMTP server to be used. + * @param port The port of the SMTP server. + * @param username An optional username, may be null. + * @param password An optional password, may be null, but only if username is null as well. + * @see #Mailer(ServerConfig, TransportStrategy, ProxyConfig) + */ + public Mailer(final String host, final Integer port, final String username, final String password) { + this(new ServerConfig(host, port, username, password), TransportStrategy.SMTP_PLAIN, ProxyConfig.SKIP_PROXY_CONFIG); + } + + /** + * Common case constructor which produces a new {@link Session} on the fly, using default vanilla SMTP transport protocol. + * + * @param serverConfig Remote SMTP server details. + * @see #Mailer(ServerConfig, TransportStrategy, ProxyConfig) + */ + public Mailer(ServerConfig serverConfig) { + this(serverConfig, TransportStrategy.SMTP_PLAIN, ProxyConfig.SKIP_PROXY_CONFIG); + } + + /** + * Common case constructor which produces a new {@link Session} on the fly. Use this if you don't have a mail session configured in your + * web container, or Spring context etc. + * + * @param host The address URL of the SMTP server to be used. + * @param port The port of the SMTP server. + * @param username An optional username, may be null. + * @param password An optional password, may be null, but only if username is null as well. + * @param transportStrategy The transport protocol configuration type for handling SSL or TLS (or vanilla SMTP) + * @see #Mailer(ServerConfig, TransportStrategy, ProxyConfig) + */ + public Mailer(final String host, final Integer port, final String username, final String password, + final TransportStrategy transportStrategy) { + this(new ServerConfig(host, port, username, password), transportStrategy, ProxyConfig.SKIP_PROXY_CONFIG); + } + + /** + * Produces a new {@link Session} on the fly. Use this if you don't have a mail session configured in your web container, or Spring + * context etc. + * + * @param serverConfig Remote SMTP server details. + * @param transportStrategy The transport protocol configuration type for handling SSL or TLS (or vanilla SMTP) + * @see #Mailer(ServerConfig, TransportStrategy, ProxyConfig) + */ + public Mailer(ServerConfig serverConfig, final TransportStrategy transportStrategy) { + this(serverConfig, transportStrategy, ProxyConfig.SKIP_PROXY_CONFIG); + } + + /** + * Produces a new {@link Session} on the fly, using default vanilla SMTP transport protocol. Use this if you don't have a mail session + * configured in your web container, or Spring context etc. + * + * @param serverConfig Remote SMTP server details. + * @param proxyConfig Remote proxy server details, if the connection should be run through a SOCKS proxy. + * @see #Mailer(ServerConfig, TransportStrategy, ProxyConfig) + */ + public Mailer(ServerConfig serverConfig, final ProxyConfig proxyConfig) { + this(serverConfig, TransportStrategy.SMTP_PLAIN, proxyConfig); + } + + /** + * Main constructor which produces a new {@link Session} on the fly. Use this if you don't have a mail session configured in your web + * container, or Spring context etc. + * + * @param serverConfig Remote SMTP server details. + * @param transportStrategy The transport protocol configuration type for handling SSL or TLS (or vanilla SMTP) + * @param proxyConfig Remote proxy server details, if the connection should be run through a SOCKS proxy. + */ + public Mailer(ServerConfig serverConfig, final TransportStrategy transportStrategy, ProxyConfig proxyConfig) { + this.transportStrategy = transportStrategy; + this.session = createMailSession(serverConfig, proxyConfig); + this.emailAddressCriteria = null; + } + + /** + * Actually instantiates and configures the {@link Session} instance. Delegates resolving transport protocol specific properties to the + * {@link #transportStrategy} in two ways:

  1. request an initial property list which the strategy may pre-populate
  2. by + * requesting the property names according to the respective transport protocol it handles (for the host property for example it would + * be "mail.smtp.host" for SMTP and "mail.smtps.host" for SMTPS)
+ *

+ * Furthermore adds proxy SOCKS properties if a proxy configuration was provided, overwriting any SOCKS properties already present. + * + * @param serverConfig Remote SMTP server details. + * @param proxyConfig Remote proxy server details, if the connection should be run through a SOCKS proxy. + * @return A fully configured Session instance complete with transport protocol settings. + * @see TransportStrategy#generateProperties() + * @see TransportStrategy#propertyNameHost() + * @see TransportStrategy#propertyNamePort() + * @see TransportStrategy#propertyNameUsername() + * @see TransportStrategy#propertyNameAuthenticate() + * @see #configureSessionWithProxy(ProxyConfig, Properties, TransportStrategy) + */ + @SuppressWarnings("WeakerAccess") + protected Session createMailSession(final ServerConfig serverConfig, final ProxyConfig proxyConfig) { + if (transportStrategy == null) { + LOGGER.warn("Transport Strategy not set, using plain SMTP strategy instead."); + transportStrategy = TransportStrategy.SMTP_PLAIN; + } + Properties props = transportStrategy.generateProperties(); + props.put(transportStrategy.propertyNameHost(), serverConfig.getHost()); + //noinspection StatementWithEmptyBody + if (serverConfig.getPort() != null) { + props.put(transportStrategy.propertyNamePort(), String.valueOf(serverConfig.getPort())); + } else { + // let JavaMail's Transport objects determine default port base don the used protocol + } + + if (serverConfig.getUsername() != null) { + props.put(transportStrategy.propertyNameUsername(), serverConfig.getUsername()); + } + + configureSessionWithProxy(proxyConfig, props, transportStrategy); + + if (serverConfig.getPassword() != null) { + props.put(transportStrategy.propertyNameAuthenticate(), "true"); + return Session.getInstance(props, new Authenticator() { + @Override + protected PasswordAuthentication getPasswordAuthentication() { + return new PasswordAuthentication(serverConfig.getUsername(), serverConfig.getPassword()); + } + }); + } else { + return Session.getInstance(props); + } + } + + /** + * If a {@link ProxyConfig} was provided with a host address, then the appropriate properties are set, overriding any SOCKS properties + * already there. + *

+ * These properties are "mail.smtp.socks.host" and "mail.smtp.socks.port", which are set to "localhost" and {@link + * ProxyConfig#getProxyBridgePort()}. + * + * @param proxyConfig Proxy server details, optionally with username / password. + * @param sessionProperties The properties to add the new configuration to. + * @param transportStrategy Used to verify if the current combination with proxy is allowed (SMTP with SSL trategy doesn't support any + * proxy, virtue of the underlying JavaMail framework). + */ + private void configureSessionWithProxy(ProxyConfig proxyConfig, Properties sessionProperties, TransportStrategy transportStrategy) { + if (!proxyConfig.requiresProxy()) { + LOGGER.debug("No proxy set, skipping proxy."); + } else { + if (transportStrategy == TransportStrategy.SMTP_SSL) { + throw new MailException(MailException.INVALID_PROXY_SLL_COMBINATION); + } + sessionProperties.put("mail.smtp.socks.host", proxyConfig.getRemoteProxyHost()); + sessionProperties.put("mail.smtp.socks.port", proxyConfig.getRemoteProxyPort()); + if (proxyConfig.requiresAuthentication()) { + sessionProperties.put("mail.smtp.socks.host", "localhost"); + sessionProperties.put("mail.smtp.socks.port", proxyConfig.getProxyBridgePort()); + proxyServer = new AnonymousSocks5Server(new AuthenticatingSocks5Bridge(proxyConfig), proxyConfig.getProxyBridgePort()); + } + } + } + + /** + * In case Simple Java Mail falls short somehow, you can get a hold of the internal {@link Session} instance to debug or tweak. Please + * let us know why you are needing this on https://github.com/bbottema/simple-java-mail/issues. + */ + public Session getSession() { + LOGGER.warn("Providing access to Session instance for emergency fall-back scenario. Please let us know why you need it."); + LOGGER.warn("\t>https://github.com/bbottema/simple-java-mail/issues"); + return session; + } + + /** + * Actually sets {@link Session#setDebug(boolean)} so that it generates debug information. To get more information out of the underlying + * JavaMail framework or out of Simple Java Mail, increase logging config of your chosen logging framework (examples here). + * + * @param debug Flag to indicate debug mode yes/no. + */ + public void setDebug(final boolean debug) { + session.setDebug(debug); + } + + /** + * Copies all property entries into the {@link Session} using {@link Session#getProperties()}. + * + * @param properties The source properties to add or override in the internal {@link Session} instance. + */ + public void applyProperties(final Properties properties) { + session.getProperties().putAll(properties); + } + + /** + * Processes an {@link Email} instance into a completely configured {@link Message}. + *

+ * Sends the Sun JavaMail {@link Message} object using {@link Session#getTransport()}. It will call {@link Transport#connect()} assuming + * all connection details have been configured in the provided {@link Session} instance. + *

+ * Performs a call to {@link Message#saveChanges()} as the Sun JavaMail API indicates it is needed to configure the message headers and + * providing a message id. + * + * @param email The information for the email to be sent. + * @throws MailException Can be thrown if an email isn't validating correctly, or some other problem occurs during connection, sending + * etc. + * @see #validate(Email) + * @see #produceMimeMessage(Email, Session) + * @see #setRecipients(Email, Message) + * @see #setTexts(Email, MimeMultipart) + * @see #setEmbeddedImages(Email, MimeMultipart) + * @see #setAttachments(Email, MimeMultipart) + */ + public final void sendMail(final Email email) + throws MailException { + if (validate(email)) { + boolean async = false; + if (async) { + new Thread() { + @Override + public void run() { + sendMailClosure(email); + } + }.start(); + } else { + sendMailClosure(email); + } + } + } + + private void sendMailClosure(Email email) { + try { + // fill and send wrapped mime message parts + MimeMessage message = produceMimeMessage(email, session); + if (email.isApplyDKIMSignature()) { + message = signMessageWithDKIM(message, email); + } + logSession(session, transportStrategy); + message.saveChanges(); // some headers and id's will be set for this specific message + Transport transport = session.getTransport(); + + try { + if (proxyServer != null) { + proxyServer.start(); + } + try { + transport.connect(); + transport.sendMessage(message, message.getAllRecipients()); + } finally { + //noinspection ThrowFromFinallyBlock + transport.close(); + } + } finally { + if (proxyServer != null) { + proxyServer.stop(); + } + } + } catch (final UnsupportedEncodingException e) { + throw new MailException(MailException.INVALID_ENCODING, e); + } catch (final MessagingException e) { + throw new MailException(MailException.GENERIC_ERROR, e); + } + } + + /** + * Simply logs host details, credentials used and whether authentication will take place and finally the transport protocol used. + */ + private void logSession(Session session, TransportStrategy transportStrategy) { + Properties properties = session.getProperties(); + final String specifics; + if (transportStrategy != null) { + final String logmsg = "starting mail session (host: %s, port: %s, username: %s, authenticate: %s, transport: %s)"; + specifics = format(logmsg, properties.get(transportStrategy.propertyNameHost()), + properties.get(transportStrategy.propertyNamePort()), properties.get(transportStrategy.propertyNameUsername()), + properties.get(transportStrategy.propertyNameAuthenticate()), transportStrategy); + } else { + specifics = properties.toString(); + } + LOGGER.debug(specifics); + } + + /** + * Validates an {@link Email} instance. Validation fails if the subject is missing, content is missing, or no recipients are defined. + * + * @param email The email that needs to be configured correctly. + * @return Always true (throws a {@link MailException} exception if validation fails). + * @throws MailException Is being thrown in any of the above causes. + * @see EmailAddressValidator + */ + @SuppressWarnings({ "SameReturnValue", "WeakerAccess" }) + public boolean validate(final Email email) + throws MailException { + if (email.getText() == null && email.getTextHTML() == null) { + throw new MailException(MailException.MISSING_CONTENT); + } else if (email.getSubject() == null || email.getSubject().equals("")) { + throw new MailException(MailException.MISSING_SUBJECT); + } else if (email.getRecipients().size() == 0) { + throw new MailException(MailException.MISSING_RECIPIENT); + } else if (email.getFromRecipient() == null) { + throw new MailException(MailException.MISSING_SENDER); + } else if (emailAddressCriteria != null) { + if (!EmailAddressValidator.isValid(email.getFromRecipient().getAddress(), emailAddressCriteria)) { + throw new MailException(format(MailException.INVALID_SENDER, email)); + } + for (final Recipient recipient : email.getRecipients()) { + if (!EmailAddressValidator.isValid(recipient.getAddress(), emailAddressCriteria)) { + throw new MailException(format(MailException.INVALID_RECIPIENT, email)); + } + } + if (email.getReplyToRecipient() != null && !EmailAddressValidator + .isValid(email.getReplyToRecipient().getAddress(), emailAddressCriteria)) { + throw new MailException(format(MailException.INVALID_REPLYTO, email)); + } + } + return true; + } + + /** + * Creates a new {@link MimeMessage} instance and prepares it in the email structure, so that it can be filled and send. + *

+ * Fills subject, from,reply-to, content, sent-date, recipients, texts, embedded images, attachments, content and adds all headers. + * + * @param email The email message from which the subject and From-address are extracted. + * @param session The Session to attach the MimeMessage to + * @return A fully preparated {@link Message} instance, ready to be sent. + * @throws MessagingException May be thrown when the message couldn't be processed by JavaMail. + * @throws UnsupportedEncodingException Zie {@link InternetAddress#InternetAddress(String, String)}. + */ + public static MimeMessage produceMimeMessage(final Email email, final Session session) + throws MessagingException, UnsupportedEncodingException { + if (email == null) { + throw new IllegalStateException("email is missing"); + } + if (session == null) { + throw new IllegalStateException("session is needed, it cannot be attached later"); + } + // create new wrapper for each mail being sent (enable sending multiple emails with one mailer) + final MimeEmailMessageWrapper messageRoot = new MimeEmailMessageWrapper(); + final MimeMessage message = new MimeMessage(session); + // set basic email properties + message.setSubject(email.getSubject(), CHARACTER_ENCODING); + message.setFrom(new InternetAddress(email.getFromRecipient().getAddress(), email.getFromRecipient().getName(), CHARACTER_ENCODING)); + setReplyTo(email, message); + setRecipients(email, message); + // fill multipart structure + setTexts(email, messageRoot.multipartAlternativeMessages); + setEmbeddedImages(email, messageRoot.multipartRelated); + setAttachments(email, messageRoot.multipartRoot); + message.setContent(messageRoot.multipartRoot); + setHeaders(email, message); + message.setSentDate(new Date()); + return message; + } + + /** + * Fills the {@link Message} instance with recipients from the {@link Email}. + * + * @param email The message in which the recipients are defined. + * @param message The javax message that needs to be filled with recipients. + * @throws UnsupportedEncodingException See {@link InternetAddress#InternetAddress(String, String)}. + * @throws MessagingException See {@link Message#addRecipient(javax.mail.Message.RecipientType, Address)} + */ + private static void setRecipients(final Email email, final Message message) + throws UnsupportedEncodingException, MessagingException { + for (final Recipient recipient : email.getRecipients()) { + final Address address = new InternetAddress(recipient.getAddress(), recipient.getName(), CHARACTER_ENCODING); + message.addRecipient(recipient.getType(), address); + } + } + + /** + * Fills the {@link Message} instance with reply-to address. + * + * @param email The message in which the recipients are defined. + * @param message The javax message that needs to be filled with reply-to address. + * @throws UnsupportedEncodingException See {@link InternetAddress#InternetAddress(String, String)}. + * @throws MessagingException See {@link Message#setReplyTo(Address[])} + */ + private static void setReplyTo(final Email email, final Message message) + throws UnsupportedEncodingException, MessagingException { + final Recipient replyToRecipient = email.getReplyToRecipient(); + if (replyToRecipient != null) { + InternetAddress replyToAddress = new InternetAddress(replyToRecipient.getAddress(), replyToRecipient.getName(), + CHARACTER_ENCODING); + message.setReplyTo(new Address[] { replyToAddress }); + } + } + + /** + * Fills the {@link Message} instance with the content bodies (text and html). + * + * @param email The message in which the content is defined. + * @param multipartAlternativeMessages See {@link MimeMultipart#addBodyPart(BodyPart)} + * @throws MessagingException See {@link BodyPart#setText(String)}, {@link BodyPart#setContent(Object, String)} and {@link + * MimeMultipart#addBodyPart(BodyPart)}. + */ + private static void setTexts(final Email email, final MimeMultipart multipartAlternativeMessages) + throws MessagingException { + if (email.getText() != null) { + final MimeBodyPart messagePart = new MimeBodyPart(); + messagePart.setText(email.getText(), CHARACTER_ENCODING); + multipartAlternativeMessages.addBodyPart(messagePart); + } + if (email.getTextHTML() != null) { + final MimeBodyPart messagePartHTML = new MimeBodyPart(); + messagePartHTML.setContent(email.getTextHTML(), "text/html; charset=\"" + CHARACTER_ENCODING + "\""); + multipartAlternativeMessages.addBodyPart(messagePartHTML); + } + } + + /** + * Fills the {@link Message} instance with the embedded images from the {@link Email}. + * + * @param email The message in which the embedded images are defined. + * @param multipartRelated The branch in the email structure in which we'll stuff the embedded images. + * @throws MessagingException See {@link MimeMultipart#addBodyPart(BodyPart)} and {@link #getBodyPartFromDatasource(AttachmentResource, + * String)} + */ + private static void setEmbeddedImages(final Email email, final MimeMultipart multipartRelated) + throws MessagingException { + for (final AttachmentResource embeddedImage : email.getEmbeddedImages()) { + multipartRelated.addBodyPart(getBodyPartFromDatasource(embeddedImage, Part.INLINE)); + } + } + + /** + * Fills the {@link Message} instance with the attachments from the {@link Email}. + * + * @param email The message in which the attachments are defined. + * @param multipartRoot The branch in the email structure in which we'll stuff the attachments. + * @throws MessagingException See {@link MimeMultipart#addBodyPart(BodyPart)} and {@link #getBodyPartFromDatasource(AttachmentResource, + * String)} + */ + private static void setAttachments(final Email email, final MimeMultipart multipartRoot) + throws MessagingException { + for (final AttachmentResource resource : email.getAttachments()) { + multipartRoot.addBodyPart(getBodyPartFromDatasource(resource, Part.ATTACHMENT)); + } + } + + /** + * Sets all headers on the {@link Message} instance. Since we're not using a high-level JavaMail method, the JavaMail library says we + * need to do some encoding and 'folding' manually, to get the value right for the headers (see {@link MimeUtility}. + * + * @param email The message in which the headers are defined. + * @param message The {@link Message} on which to set the raw, encoded and folded headers. + * @throws UnsupportedEncodingException See {@link MimeUtility#encodeText(String, String, String)} + * @throws MessagingException See {@link Message#addHeader(String, String)} + * @see MimeUtility#encodeText(String, String, String) + * @see MimeUtility#fold(int, String) + */ + private static void setHeaders(final Email email, final Message message) + throws UnsupportedEncodingException, MessagingException { + // add headers (for raw message headers we need to 'fold' them using MimeUtility + for (Map.Entry header : email.getHeaders().entrySet()) { + String headerName = header.getKey(); + String headerValue = MimeUtility.encodeText(header.getValue(), CHARACTER_ENCODING, null); + String foldedHeaderValue = MimeUtility.fold(headerName.length() + 2, headerValue); + message.addHeader(header.getKey(), foldedHeaderValue); + } + } + + /** + * Helper method which generates a {@link BodyPart} from an {@link AttachmentResource} (from its {@link DataSource}) and a disposition + * type ({@link Part#INLINE} or {@link Part#ATTACHMENT}). With this the attachment data can be converted into objects that fit in the + * email structure.

For every attachment and embedded image a header needs to be set. + * + * @param attachmentResource An object that describes the attachment and contains the actual content data. + * @param dispositionType The type of attachment, {@link Part#INLINE} or {@link Part#ATTACHMENT} . + * @return An object with the attachment data read for placement in the email structure. + * @throws MessagingException All BodyPart setters. + */ + private static BodyPart getBodyPartFromDatasource(final AttachmentResource attachmentResource, final String dispositionType) + throws MessagingException { + final BodyPart attachmentPart = new MimeBodyPart(); + final DataSource dataSource = attachmentResource.getDataSource(); + // setting headers isn't working nicely using the javax mail API, so let's do that manually + String resourceName = attachmentResource.getName(); + final boolean dataSourceNameProvided = dataSource.getName() != null && !dataSource.getName().isEmpty(); + String fileName = dataSourceNameProvided ? dataSource.getName() : resourceName; + attachmentPart.setDataHandler(new DataHandler(attachmentResource.getDataSource())); + attachmentPart.setFileName(fileName); + attachmentPart.setHeader("Content-Type", dataSource.getContentType() + "; filename=" + fileName + "; name=" + fileName); + attachmentPart.setHeader("Content-ID", format("<%s>", resourceName)); + attachmentPart.setDisposition(dispositionType + "; size=0"); + return attachmentPart; + } + + /** + * Primes the {@link MimeMessage} instance for signing with DKIM. The signing itself is performed by {@link DkimMessage} and {@link + * DkimSigner} during the physical sending of the message. + * + * @param message The message to be signed when sent. + * @param email The {@link Email} that contains the relevant signing information + * @return The original mime message wrapped in a new one that performs signing when sent. + */ + static MimeMessage signMessageWithDKIM(MimeMessage message, Email email) { + try { + final DkimSigner dkimSigner = new DkimSigner(email.getSigningDomain(), email.getSelector(), + email.getDkimPrivateKeyInputStream()); + dkimSigner.setIdentity(email.getFromRecipient().getAddress()); + dkimSigner.setHeaderCanonicalization(Canonicalization.SIMPLE); + dkimSigner.setBodyCanonicalization(Canonicalization.RELAXED); + dkimSigner.setSigningAlgorithm(SigningAlgorithm.SHA256_WITH_RSA); + dkimSigner.setLengthParam(true); + dkimSigner.setZParam(false); + return new DkimMessage(message, dkimSigner); + } catch (IOException | NoSuchAlgorithmException | InvalidKeySpecException | MessagingException e) { + throw new MailException(format(MailException.INVALID_DOMAINKEY, e.getMessage()), e); + } + } + + /** + * This class conveniently wraps all necessary mimemessage parts that need to be filled with content, attachments etc. The root is + * ultimately sent using JavaMail.

The constructor creates a new email message constructed from {@link MimeMultipart} as + * follows: + *

+ *

+	 * - root
+	 * 	- related
+	 * 		- alternative
+	 * 			- mail tekst
+	 * 			- mail html tekst
+	 * 		- embedded images
+	 * 	- attachments
+	 * 
+ * + * @author Benny Bottema + */ + private static class MimeEmailMessageWrapper { + + private final MimeMultipart multipartRoot; + + private final MimeMultipart multipartRelated; + + private final MimeMultipart multipartAlternativeMessages; + + /** + * Creates an email skeleton structure, so that embedded images, attachments and (html) texts are being processed properly. + */ + MimeEmailMessageWrapper() { + multipartRoot = new MimeMultipart("mixed"); + final MimeBodyPart contentRelated = new MimeBodyPart(); + multipartRelated = new MimeMultipart("related"); + final MimeBodyPart contentAlternativeMessages = new MimeBodyPart(); + multipartAlternativeMessages = new MimeMultipart("alternative"); + try { + // construct mail structure + multipartRoot.addBodyPart(contentRelated); + contentRelated.setContent(multipartRelated); + multipartRelated.addBodyPart(contentAlternativeMessages); + contentAlternativeMessages.setContent(multipartAlternativeMessages); + } catch (final MessagingException e) { + throw new MailException(e.getMessage(), e); + } + } + + } + + /** + * Overrides the default email address validation restrictions {@link #emailAddressCriteria} when validating and sending emails using + * the current Mailer instance. + */ + public void setEmailAddressCriteria(EnumSet emailAddressCriteria) { + this.emailAddressCriteria = emailAddressCriteria; + } +} diff --git a/src/main/java/org/codemonkey/simplejavamail/ProxyConfig.java b/src/main/java/org/simplejavamail/ProxyConfig.java similarity index 93% rename from src/main/java/org/codemonkey/simplejavamail/ProxyConfig.java rename to src/main/java/org/simplejavamail/ProxyConfig.java index 220518a72..c4e715dee 100644 --- a/src/main/java/org/codemonkey/simplejavamail/ProxyConfig.java +++ b/src/main/java/org/simplejavamail/ProxyConfig.java @@ -1,7 +1,8 @@ -package org.codemonkey.simplejavamail; +package org.simplejavamail; + +import org.simplejavamail.internal.Util; import static java.lang.String.format; -import static org.codemonkey.simplejavamail.internal.Util.checkNotNull; /** * The proxy configuration that indicates whether the connections should be routed through a proxy. @@ -62,8 +63,8 @@ public ProxyConfig(String remoteProxyHost, int remoteProxyPort) { */ @SuppressWarnings({ "WeakerAccess", "SameParameterValue" }) public ProxyConfig(String remoteProxyHost, int remoteProxyPort, String username, String password) { - this.remoteProxyHost = checkNotNull(remoteProxyHost, "remoteProxyHost missing"); - this.remoteProxyPort = checkNotNull(remoteProxyPort, "remoteProxyPort missing"); + this.remoteProxyHost = Util.checkNotNull(remoteProxyHost, "remoteProxyHost missing"); + this.remoteProxyPort = Util.checkNotNull(remoteProxyPort, "remoteProxyPort missing"); this.username = username; this.password = password; if (username != null && password == null) { diff --git a/src/main/java/org/codemonkey/simplejavamail/ServerConfig.java b/src/main/java/org/simplejavamail/ServerConfig.java similarity index 96% rename from src/main/java/org/codemonkey/simplejavamail/ServerConfig.java rename to src/main/java/org/simplejavamail/ServerConfig.java index 71571d069..422a40dd3 100644 --- a/src/main/java/org/codemonkey/simplejavamail/ServerConfig.java +++ b/src/main/java/org/simplejavamail/ServerConfig.java @@ -1,4 +1,4 @@ -package org.codemonkey.simplejavamail; +package org.simplejavamail; public class ServerConfig { private final String host; diff --git a/src/main/java/org/codemonkey/simplejavamail/TransportStrategy.java b/src/main/java/org/simplejavamail/TransportStrategy.java similarity index 95% rename from src/main/java/org/codemonkey/simplejavamail/TransportStrategy.java rename to src/main/java/org/simplejavamail/TransportStrategy.java index a28e54ca8..0abe06abc 100644 --- a/src/main/java/org/codemonkey/simplejavamail/TransportStrategy.java +++ b/src/main/java/org/simplejavamail/TransportStrategy.java @@ -1,240 +1,240 @@ -package org.codemonkey.simplejavamail; - -import javax.mail.Session; -import java.util.Properties; - -/** - * Defines the various types of transport protocols and implements respective properties so that a {@link Session} may be configured using a - * TransportStrategy implementation. - * - * @author Benny Bottema - */ -public enum TransportStrategy { - - /** - * Simplest possible form: only vanilla ".smtp." property names and no extra properties. Additionally the transport protocol is - * explicitly set to smtp. - */ - SMTP_PLAIN { - /** - * Here protocol "mail.transport.protocol" is set to "smtp". - * - * @see TransportStrategy#SMTP_PLAIN - */ - @Override - public Properties generateProperties() { - final Properties props = super.generateProperties(); - props.put("mail.transport.protocol", "smtp"); - return props; - } - - /** - * @return "mail.smtp.host" - */ - @Override - String propertyNameHost() { - return "mail.smtp.host"; - } - - /** - * @return "mail.smtp.port" - */ - @Override - String propertyNamePort() { - return "mail.smtp.port"; - } - - /** - * @return "mail.smtp.username" - */ - @Override - String propertyNameUsername() { - return "mail.smtp.username"; - } - - /** - * @return "mail.smtp.auth" - */ - @Override - String propertyNameAuthenticate() { - return "mail.smtp.auth"; - } - - /** - * @return Whether Session is configured for vanilla SMTP. - */ - @Override - public boolean sessionConfigured(Session session) { - return "smtp".equals(session.getProperties().getProperty("mail.transport.protocol")); - } - }, - /** - * SMTPS / SSL transport strategy, that returns the ".smtps." variation of the SMTP_PLAIN version. Additionally the transport protocol - * is explicitly set to smtps. Finally, he property "mail.smtps.quitwait" is set to false, to get rid of a strange SSL exception:
- * - *
-	 * javax.mail.MessagingException: Exception reading response;
-	 * nested exception is:
-	 * 	javax.net.ssl.SSLException: Unsupported record version Unknown-50.49
-	 * (..)
-	 * 
- * - *
The mail is sent but the exception is unwanted. The property quitwait means If set to false, the QUIT command is sent - * and the connection is immediately closed. If set to true (the default), causes the transport to wait for the response to the QUIT - * command

- * - source - */ - SMTP_SSL { - /** - * Here protocol "mail.transport.protocol" is set to "smtps" and the quitwait property "mail.smtps.quitwait" is set to "false". - * - * @see TransportStrategy#SMTP_SSL - */ - @Override - public Properties generateProperties() { - final Properties props = super.generateProperties(); - props.put("mail.transport.protocol", "smtps"); - props.put("mail.smtps.quitwait", "false"); - return props; - } - - /** - * @return "mail.smtps.host" - */ - @Override - String propertyNameHost() { - return "mail.smtps.host"; - } - - /** - * @return "mail.smtps.port" - */ - @Override - String propertyNamePort() { - return "mail.smtps.port"; - } - - /** - * @return "mail.smtps.username" - */ - @Override - String propertyNameUsername() { - return "mail.smtps.username"; - } - - /** - * @return "mail.smtps.auth" - */ - @Override - String propertyNameAuthenticate() { - return "mail.smtps.auth"; - } - - /** - * @return Whether Session is configured for SSL. - */ - @Override - public boolean sessionConfigured(Session session) { - return "smtps".equals(session.getProperties().getProperty("mail.transport.protocol")); - } - }, - /** - * NOTE: this code is in untested beta state - *

- * Uses standard ".smtp." property names (like {@link TransportStrategy#SMTP_PLAIN}). Additionally the transport protocol is explicitly - * set to smtp. Finally, the property "mail.smtp.starttls.enable" is being set to true. - */ - SMTP_TLS { - - /** - * Here protocol "mail.transport.protocol" is set to "smtp" and the tls property "mail.smtp.starttls.enable" is set to "true". - * - * @see TransportStrategy#SMTP_TLS - */ - @Override - public Properties generateProperties() { - final Properties props = super.generateProperties(); - props.put("mail.transport.protocol", "smtp"); - props.put("mail.smtp.starttls.enable", "true"); - return props; - } - - /** - * @return "mail.smtp.host" - */ - @Override - String propertyNameHost() { - return "mail.smtp.host"; - } - - /** - * @return "mail.smtp.port" - */ - @Override - String propertyNamePort() { - return "mail.smtp.port"; - } - - /** - * @return "mail.smtp.username" - */ - @Override - String propertyNameUsername() { - return "mail.smtp.username"; - } - - /** - * @return "mail.smtp.auth" - */ - @Override - String propertyNameAuthenticate() { - return "mail.smtp.auth"; - } - - /** - * @return Whether Session is configured for TLS. - */ - @Override - public boolean sessionConfigured(Session session) { - return "smtp".equals(session.getProperties().getProperty("mail.transport.protocol")) && - "true".equals(session.getProperties().getProperty("mail.smtp.starttls.enable")); - } - }; - - /** - * Base implementation that simply returns an empty list of properties. Should be overridden by the various strategies where - * appropriate. - * - * @return An empty Properties instance. - */ - public Properties generateProperties() { - return new Properties(); - } - - abstract String propertyNameHost(); - - abstract String propertyNamePort(); - - abstract String propertyNameUsername(); - - abstract String propertyNameAuthenticate(); - - /** - * @return Whether Session is configured with a strategy pattern. - */ - abstract boolean sessionConfigured(Session session); - - /** - * @param session The session to determine the current transport strategy for - * @return Which strategy matches the current Session properties. - * @see #sessionConfigured(Session) - */ - public static TransportStrategy findStrategyForSession(Session session) { - for (TransportStrategy strategy : TransportStrategy.values()) { - if (strategy.sessionConfigured(session)) { - return strategy; - } - } - return null; - } +package org.simplejavamail; + +import javax.mail.Session; +import java.util.Properties; + +/** + * Defines the various types of transport protocols and implements respective properties so that a {@link Session} may be configured using a + * TransportStrategy implementation. + * + * @author Benny Bottema + */ +public enum TransportStrategy { + + /** + * Simplest possible form: only vanilla ".smtp." property names and no extra properties. Additionally the transport protocol is + * explicitly set to smtp. + */ + SMTP_PLAIN { + /** + * Here protocol "mail.transport.protocol" is set to "smtp". + * + * @see TransportStrategy#SMTP_PLAIN + */ + @Override + public Properties generateProperties() { + final Properties props = super.generateProperties(); + props.put("mail.transport.protocol", "smtp"); + return props; + } + + /** + * @return "mail.smtp.host" + */ + @Override + String propertyNameHost() { + return "mail.smtp.host"; + } + + /** + * @return "mail.smtp.port" + */ + @Override + String propertyNamePort() { + return "mail.smtp.port"; + } + + /** + * @return "mail.smtp.username" + */ + @Override + String propertyNameUsername() { + return "mail.smtp.username"; + } + + /** + * @return "mail.smtp.auth" + */ + @Override + String propertyNameAuthenticate() { + return "mail.smtp.auth"; + } + + /** + * @return Whether Session is configured for vanilla SMTP. + */ + @Override + public boolean sessionConfigured(Session session) { + return "smtp".equals(session.getProperties().getProperty("mail.transport.protocol")); + } + }, + /** + * SMTPS / SSL transport strategy, that returns the ".smtps." variation of the SMTP_PLAIN version. Additionally the transport protocol + * is explicitly set to smtps. Finally, he property "mail.smtps.quitwait" is set to false, to get rid of a strange SSL exception:
+ * + *

+	 * javax.mail.MessagingException: Exception reading response;
+	 * nested exception is:
+	 * 	javax.net.ssl.SSLException: Unsupported record version Unknown-50.49
+	 * (..)
+	 * 
+ * + *
The mail is sent but the exception is unwanted. The property quitwait means If set to false, the QUIT command is sent + * and the connection is immediately closed. If set to true (the default), causes the transport to wait for the response to the QUIT + * command

+ * - source + */ + SMTP_SSL { + /** + * Here protocol "mail.transport.protocol" is set to "smtps" and the quitwait property "mail.smtps.quitwait" is set to "false". + * + * @see TransportStrategy#SMTP_SSL + */ + @Override + public Properties generateProperties() { + final Properties props = super.generateProperties(); + props.put("mail.transport.protocol", "smtps"); + props.put("mail.smtps.quitwait", "false"); + return props; + } + + /** + * @return "mail.smtps.host" + */ + @Override + String propertyNameHost() { + return "mail.smtps.host"; + } + + /** + * @return "mail.smtps.port" + */ + @Override + String propertyNamePort() { + return "mail.smtps.port"; + } + + /** + * @return "mail.smtps.username" + */ + @Override + String propertyNameUsername() { + return "mail.smtps.username"; + } + + /** + * @return "mail.smtps.auth" + */ + @Override + String propertyNameAuthenticate() { + return "mail.smtps.auth"; + } + + /** + * @return Whether Session is configured for SSL. + */ + @Override + public boolean sessionConfigured(Session session) { + return "smtps".equals(session.getProperties().getProperty("mail.transport.protocol")); + } + }, + /** + * NOTE: this code is in untested beta state + *

+ * Uses standard ".smtp." property names (like {@link TransportStrategy#SMTP_PLAIN}). Additionally the transport protocol is explicitly + * set to smtp. Finally, the property "mail.smtp.starttls.enable" is being set to true. + */ + SMTP_TLS { + + /** + * Here protocol "mail.transport.protocol" is set to "smtp" and the tls property "mail.smtp.starttls.enable" is set to "true". + * + * @see TransportStrategy#SMTP_TLS + */ + @Override + public Properties generateProperties() { + final Properties props = super.generateProperties(); + props.put("mail.transport.protocol", "smtp"); + props.put("mail.smtp.starttls.enable", "true"); + return props; + } + + /** + * @return "mail.smtp.host" + */ + @Override + String propertyNameHost() { + return "mail.smtp.host"; + } + + /** + * @return "mail.smtp.port" + */ + @Override + String propertyNamePort() { + return "mail.smtp.port"; + } + + /** + * @return "mail.smtp.username" + */ + @Override + String propertyNameUsername() { + return "mail.smtp.username"; + } + + /** + * @return "mail.smtp.auth" + */ + @Override + String propertyNameAuthenticate() { + return "mail.smtp.auth"; + } + + /** + * @return Whether Session is configured for TLS. + */ + @Override + public boolean sessionConfigured(Session session) { + return "smtp".equals(session.getProperties().getProperty("mail.transport.protocol")) && + "true".equals(session.getProperties().getProperty("mail.smtp.starttls.enable")); + } + }; + + /** + * Base implementation that simply returns an empty list of properties. Should be overridden by the various strategies where + * appropriate. + * + * @return An empty Properties instance. + */ + public Properties generateProperties() { + return new Properties(); + } + + abstract String propertyNameHost(); + + abstract String propertyNamePort(); + + abstract String propertyNameUsername(); + + abstract String propertyNameAuthenticate(); + + /** + * @return Whether Session is configured with a strategy pattern. + */ + abstract boolean sessionConfigured(Session session); + + /** + * @param session The session to determine the current transport strategy for + * @return Which strategy matches the current Session properties. + * @see #sessionConfigured(Session) + */ + public static TransportStrategy findStrategyForSession(Session session) { + for (TransportStrategy strategy : TransportStrategy.values()) { + if (strategy.sessionConfigured(session)) { + return strategy; + } + } + return null; + } } \ No newline at end of file diff --git a/src/main/java/org/codemonkey/simplejavamail/email/AttachmentResource.java b/src/main/java/org/simplejavamail/email/AttachmentResource.java similarity index 97% rename from src/main/java/org/codemonkey/simplejavamail/email/AttachmentResource.java rename to src/main/java/org/simplejavamail/email/AttachmentResource.java index 792dada78..5f59352e1 100644 --- a/src/main/java/org/codemonkey/simplejavamail/email/AttachmentResource.java +++ b/src/main/java/org/simplejavamail/email/AttachmentResource.java @@ -1,4 +1,4 @@ -package org.codemonkey.simplejavamail.email; +package org.simplejavamail.email; import javax.activation.DataSource; diff --git a/src/main/java/org/codemonkey/simplejavamail/email/Email.java b/src/main/java/org/simplejavamail/email/Email.java similarity index 99% rename from src/main/java/org/codemonkey/simplejavamail/email/Email.java rename to src/main/java/org/simplejavamail/email/Email.java index fb7300ae8..951e558af 100644 --- a/src/main/java/org/codemonkey/simplejavamail/email/Email.java +++ b/src/main/java/org/simplejavamail/email/Email.java @@ -1,6 +1,6 @@ -package org.codemonkey.simplejavamail.email; +package org.simplejavamail.email; -import org.codemonkey.simplejavamail.util.MimeMessageParser; +import org.simplejavamail.util.MimeMessageParser; import javax.activation.DataSource; import javax.mail.Message.RecipientType; diff --git a/src/main/java/org/codemonkey/simplejavamail/email/EmailException.java b/src/main/java/org/simplejavamail/email/EmailException.java similarity index 84% rename from src/main/java/org/codemonkey/simplejavamail/email/EmailException.java rename to src/main/java/org/simplejavamail/email/EmailException.java index 2dfe51baa..083d39b02 100644 --- a/src/main/java/org/codemonkey/simplejavamail/email/EmailException.java +++ b/src/main/java/org/simplejavamail/email/EmailException.java @@ -1,6 +1,6 @@ -package org.codemonkey.simplejavamail.email; +package org.simplejavamail.email; -import org.codemonkey.simplejavamail.MailException; +import org.simplejavamail.MailException; /** * This exception is used to communicate errors during the creation of an email. diff --git a/src/main/java/org/codemonkey/simplejavamail/email/EqualsHelper.java b/src/main/java/org/simplejavamail/email/EqualsHelper.java similarity index 98% rename from src/main/java/org/codemonkey/simplejavamail/email/EqualsHelper.java rename to src/main/java/org/simplejavamail/email/EqualsHelper.java index 583788a5c..b6e97ca3a 100644 --- a/src/main/java/org/codemonkey/simplejavamail/email/EqualsHelper.java +++ b/src/main/java/org/simplejavamail/email/EqualsHelper.java @@ -1,4 +1,4 @@ -package org.codemonkey.simplejavamail.email; +package org.simplejavamail.email; import javax.activation.DataSource; import java.util.List; diff --git a/src/main/java/org/codemonkey/simplejavamail/email/Recipient.java b/src/main/java/org/simplejavamail/email/Recipient.java similarity index 96% rename from src/main/java/org/codemonkey/simplejavamail/email/Recipient.java rename to src/main/java/org/simplejavamail/email/Recipient.java index 12b207534..06c3474a4 100644 --- a/src/main/java/org/codemonkey/simplejavamail/email/Recipient.java +++ b/src/main/java/org/simplejavamail/email/Recipient.java @@ -1,4 +1,4 @@ -package org.codemonkey.simplejavamail.email; +package org.simplejavamail.email; import javax.mail.Message.RecipientType; diff --git a/src/main/java/org/codemonkey/simplejavamail/internal/Util.java b/src/main/java/org/simplejavamail/internal/Util.java similarity index 92% rename from src/main/java/org/codemonkey/simplejavamail/internal/Util.java rename to src/main/java/org/simplejavamail/internal/Util.java index 3f578bc8d..27e822394 100644 --- a/src/main/java/org/codemonkey/simplejavamail/internal/Util.java +++ b/src/main/java/org/simplejavamail/internal/Util.java @@ -1,4 +1,4 @@ -package org.codemonkey.simplejavamail.internal; +package org.simplejavamail.internal; import static java.lang.Integer.toHexString; diff --git a/src/main/java/org/codemonkey/simplejavamail/internal/socks/AuthenticatingSocks5Bridge.java b/src/main/java/org/simplejavamail/internal/socks/AuthenticatingSocks5Bridge.java similarity index 93% rename from src/main/java/org/codemonkey/simplejavamail/internal/socks/AuthenticatingSocks5Bridge.java rename to src/main/java/org/simplejavamail/internal/socks/AuthenticatingSocks5Bridge.java index f1e676f01..0abef2074 100644 --- a/src/main/java/org/codemonkey/simplejavamail/internal/socks/AuthenticatingSocks5Bridge.java +++ b/src/main/java/org/simplejavamail/internal/socks/AuthenticatingSocks5Bridge.java @@ -1,8 +1,8 @@ -package org.codemonkey.simplejavamail.internal.socks; +package org.simplejavamail.internal.socks; -import org.codemonkey.simplejavamail.ProxyConfig; -import org.codemonkey.simplejavamail.internal.socks.common.Socks5Bridge; -import org.codemonkey.simplejavamail.internal.socks.socks5client.*; +import org.simplejavamail.ProxyConfig; +import org.simplejavamail.internal.socks.common.Socks5Bridge; +import org.simplejavamail.internal.socks.socks5client.*; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/src/main/java/org/codemonkey/simplejavamail/internal/socks/common/Socks5Bridge.java b/src/main/java/org/simplejavamail/internal/socks/common/Socks5Bridge.java similarity index 64% rename from src/main/java/org/codemonkey/simplejavamail/internal/socks/common/Socks5Bridge.java rename to src/main/java/org/simplejavamail/internal/socks/common/Socks5Bridge.java index 1c965271b..705c27d39 100644 --- a/src/main/java/org/codemonkey/simplejavamail/internal/socks/common/Socks5Bridge.java +++ b/src/main/java/org/simplejavamail/internal/socks/common/Socks5Bridge.java @@ -1,4 +1,7 @@ -package org.codemonkey.simplejavamail.internal.socks.common; +package org.simplejavamail.internal.socks.common; + +import org.simplejavamail.internal.socks.socks5client.Socks5; +import org.simplejavamail.internal.socks.socks5server.AnonymousSocks5Server; import java.io.IOException; import java.net.InetAddress; @@ -8,12 +11,12 @@ * Clean seperation between the server and client packages. This bridge acts as gateway from the temporary intermediary SOCKS5 server to the * remote proxy. *

- * This Bridge connects the {@link org.codemonkey.simplejavamail.internal.socks.socks5server.AnonymousSocks5Server} server and the {@link - * org.codemonkey.simplejavamail.internal.socks.socks5client.Socks5} client. + * This Bridge connects the {@link AnonymousSocks5Server} server and the {@link + * Socks5} client. */ public interface Socks5Bridge { /** - * Generates a {@link Socket} using {@link org.codemonkey.simplejavamail.internal.socks.socks5client.Socks5} connected to authenticated + * Generates a {@link Socket} using {@link Socks5} connected to authenticated * proxy. * * @param sessionId The current email session context. diff --git a/src/main/java/org/codemonkey/simplejavamail/internal/socks/common/SocksException.java b/src/main/java/org/simplejavamail/internal/socks/common/SocksException.java similarity index 92% rename from src/main/java/org/codemonkey/simplejavamail/internal/socks/common/SocksException.java rename to src/main/java/org/simplejavamail/internal/socks/common/SocksException.java index 8b368b9d8..666e2216f 100644 --- a/src/main/java/org/codemonkey/simplejavamail/internal/socks/common/SocksException.java +++ b/src/main/java/org/simplejavamail/internal/socks/common/SocksException.java @@ -1,6 +1,6 @@ -package org.codemonkey.simplejavamail.internal.socks.common; +package org.simplejavamail.internal.socks.common; public class SocksException extends RuntimeException { diff --git a/src/main/java/org/codemonkey/simplejavamail/internal/socks/socks5client/KeyStoreInfo.java b/src/main/java/org/simplejavamail/internal/socks/socks5client/KeyStoreInfo.java similarity index 88% rename from src/main/java/org/codemonkey/simplejavamail/internal/socks/socks5client/KeyStoreInfo.java rename to src/main/java/org/simplejavamail/internal/socks/socks5client/KeyStoreInfo.java index e0600eac4..3b88c47a9 100644 --- a/src/main/java/org/codemonkey/simplejavamail/internal/socks/socks5client/KeyStoreInfo.java +++ b/src/main/java/org/simplejavamail/internal/socks/socks5client/KeyStoreInfo.java @@ -1,8 +1,8 @@ -package org.codemonkey.simplejavamail.internal.socks.socks5client; +package org.simplejavamail.internal.socks.socks5client; -import org.codemonkey.simplejavamail.internal.Util; +import org.simplejavamail.internal.Util; @SuppressWarnings("SameParameterValue") public class KeyStoreInfo { diff --git a/src/main/java/org/codemonkey/simplejavamail/internal/socks/socks5client/ProxyCredentials.java b/src/main/java/org/simplejavamail/internal/socks/socks5client/ProxyCredentials.java similarity index 78% rename from src/main/java/org/codemonkey/simplejavamail/internal/socks/socks5client/ProxyCredentials.java rename to src/main/java/org/simplejavamail/internal/socks/socks5client/ProxyCredentials.java index 89e303028..8f246c181 100644 --- a/src/main/java/org/codemonkey/simplejavamail/internal/socks/socks5client/ProxyCredentials.java +++ b/src/main/java/org/simplejavamail/internal/socks/socks5client/ProxyCredentials.java @@ -1,8 +1,8 @@ -package org.codemonkey.simplejavamail.internal.socks.socks5client; +package org.simplejavamail.internal.socks.socks5client; -import org.codemonkey.simplejavamail.internal.Util; +import org.simplejavamail.internal.Util; public class ProxyCredentials { diff --git a/src/main/java/org/codemonkey/simplejavamail/internal/socks/socks5client/SSLConfiguration.java b/src/main/java/org/simplejavamail/internal/socks/socks5client/SSLConfiguration.java similarity index 92% rename from src/main/java/org/codemonkey/simplejavamail/internal/socks/socks5client/SSLConfiguration.java rename to src/main/java/org/simplejavamail/internal/socks/socks5client/SSLConfiguration.java index 174ad0a17..10dce26ce 100644 --- a/src/main/java/org/codemonkey/simplejavamail/internal/socks/socks5client/SSLConfiguration.java +++ b/src/main/java/org/simplejavamail/internal/socks/socks5client/SSLConfiguration.java @@ -1,9 +1,9 @@ -package org.codemonkey.simplejavamail.internal.socks.socks5client; +package org.simplejavamail.internal.socks.socks5client; -import org.codemonkey.simplejavamail.internal.socks.common.SocksException; -import org.codemonkey.simplejavamail.internal.Util; +import org.simplejavamail.internal.socks.common.SocksException; +import org.simplejavamail.internal.Util; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/src/main/java/org/codemonkey/simplejavamail/internal/socks/socks5client/SSLSocks5.java b/src/main/java/org/simplejavamail/internal/socks/socks5client/SSLSocks5.java similarity index 95% rename from src/main/java/org/codemonkey/simplejavamail/internal/socks/socks5client/SSLSocks5.java rename to src/main/java/org/simplejavamail/internal/socks/socks5client/SSLSocks5.java index 602a201c6..bf5861296 100644 --- a/src/main/java/org/codemonkey/simplejavamail/internal/socks/socks5client/SSLSocks5.java +++ b/src/main/java/org/simplejavamail/internal/socks/socks5client/SSLSocks5.java @@ -1,6 +1,6 @@ -package org.codemonkey.simplejavamail.internal.socks.socks5client; +package org.simplejavamail.internal.socks.socks5client; import java.io.IOException; import java.net.InetAddress; diff --git a/src/main/java/org/codemonkey/simplejavamail/internal/socks/socks5client/Socks5.java b/src/main/java/org/simplejavamail/internal/socks/socks5client/Socks5.java similarity index 98% rename from src/main/java/org/codemonkey/simplejavamail/internal/socks/socks5client/Socks5.java rename to src/main/java/org/simplejavamail/internal/socks/socks5client/Socks5.java index 576913aff..f295b670a 100644 --- a/src/main/java/org/codemonkey/simplejavamail/internal/socks/socks5client/Socks5.java +++ b/src/main/java/org/simplejavamail/internal/socks/socks5client/Socks5.java @@ -1,6 +1,6 @@ -package org.codemonkey.simplejavamail.internal.socks.socks5client; +package org.simplejavamail.internal.socks.socks5client; import java.io.IOException; import java.io.InputStream; diff --git a/src/main/java/org/codemonkey/simplejavamail/internal/socks/socks5client/SocksAuthenticationHelper.java b/src/main/java/org/simplejavamail/internal/socks/socks5client/SocksAuthenticationHelper.java similarity index 95% rename from src/main/java/org/codemonkey/simplejavamail/internal/socks/socks5client/SocksAuthenticationHelper.java rename to src/main/java/org/simplejavamail/internal/socks/socks5client/SocksAuthenticationHelper.java index f06a04682..96ca6573a 100644 --- a/src/main/java/org/codemonkey/simplejavamail/internal/socks/socks5client/SocksAuthenticationHelper.java +++ b/src/main/java/org/simplejavamail/internal/socks/socks5client/SocksAuthenticationHelper.java @@ -1,9 +1,9 @@ -package org.codemonkey.simplejavamail.internal.socks.socks5client; +package org.simplejavamail.internal.socks.socks5client; -import org.codemonkey.simplejavamail.internal.socks.common.SocksException; -import org.codemonkey.simplejavamail.internal.Util; +import org.simplejavamail.internal.socks.common.SocksException; +import org.simplejavamail.internal.Util; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/src/main/java/org/codemonkey/simplejavamail/internal/socks/socks5client/SocksCommandSender.java b/src/main/java/org/simplejavamail/internal/socks/socks5client/SocksCommandSender.java similarity index 96% rename from src/main/java/org/codemonkey/simplejavamail/internal/socks/socks5client/SocksCommandSender.java rename to src/main/java/org/simplejavamail/internal/socks/socks5client/SocksCommandSender.java index 674f2cec9..78b1f9bd6 100644 --- a/src/main/java/org/codemonkey/simplejavamail/internal/socks/socks5client/SocksCommandSender.java +++ b/src/main/java/org/simplejavamail/internal/socks/socks5client/SocksCommandSender.java @@ -1,9 +1,9 @@ -package org.codemonkey.simplejavamail.internal.socks.socks5client; +package org.simplejavamail.internal.socks.socks5client; -import org.codemonkey.simplejavamail.internal.Util; -import org.codemonkey.simplejavamail.internal.socks.common.SocksException; +import org.simplejavamail.internal.Util; +import org.simplejavamail.internal.socks.common.SocksException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/src/main/java/org/codemonkey/simplejavamail/internal/socks/socks5client/SocksSocket.java b/src/main/java/org/simplejavamail/internal/socks/socks5client/SocksSocket.java similarity index 97% rename from src/main/java/org/codemonkey/simplejavamail/internal/socks/socks5client/SocksSocket.java rename to src/main/java/org/simplejavamail/internal/socks/socks5client/SocksSocket.java index a800e8449..83dbb3604 100644 --- a/src/main/java/org/codemonkey/simplejavamail/internal/socks/socks5client/SocksSocket.java +++ b/src/main/java/org/simplejavamail/internal/socks/socks5client/SocksSocket.java @@ -1,9 +1,9 @@ -package org.codemonkey.simplejavamail.internal.socks.socks5client; +package org.simplejavamail.internal.socks.socks5client; -import org.codemonkey.simplejavamail.internal.socks.common.SocksException; -import org.codemonkey.simplejavamail.internal.Util; +import org.simplejavamail.internal.socks.common.SocksException; +import org.simplejavamail.internal.Util; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/src/main/java/org/codemonkey/simplejavamail/internal/socks/socks5server/AddressType.java b/src/main/java/org/simplejavamail/internal/socks/socks5server/AddressType.java similarity index 78% rename from src/main/java/org/codemonkey/simplejavamail/internal/socks/socks5server/AddressType.java rename to src/main/java/org/simplejavamail/internal/socks/socks5server/AddressType.java index 1c59aa1f9..c7788e62c 100644 --- a/src/main/java/org/codemonkey/simplejavamail/internal/socks/socks5server/AddressType.java +++ b/src/main/java/org/simplejavamail/internal/socks/socks5server/AddressType.java @@ -1,4 +1,4 @@ -package org.codemonkey.simplejavamail.internal.socks.socks5server; +package org.simplejavamail.internal.socks.socks5server; public class AddressType { diff --git a/src/main/java/org/codemonkey/simplejavamail/internal/socks/socks5server/AnonymousSocks5Server.java b/src/main/java/org/simplejavamail/internal/socks/socks5server/AnonymousSocks5Server.java similarity index 89% rename from src/main/java/org/codemonkey/simplejavamail/internal/socks/socks5server/AnonymousSocks5Server.java rename to src/main/java/org/simplejavamail/internal/socks/socks5server/AnonymousSocks5Server.java index 4c5202f74..4166f6ece 100644 --- a/src/main/java/org/codemonkey/simplejavamail/internal/socks/socks5server/AnonymousSocks5Server.java +++ b/src/main/java/org/simplejavamail/internal/socks/socks5server/AnonymousSocks5Server.java @@ -1,7 +1,7 @@ -package org.codemonkey.simplejavamail.internal.socks.socks5server; +package org.simplejavamail.internal.socks.socks5server; -import org.codemonkey.simplejavamail.internal.socks.common.Socks5Bridge; -import org.codemonkey.simplejavamail.internal.socks.common.SocksException; +import org.simplejavamail.internal.socks.common.Socks5Bridge; +import org.simplejavamail.internal.socks.common.SocksException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/src/main/java/org/codemonkey/simplejavamail/internal/socks/socks5server/Socks5Handler.java b/src/main/java/org/simplejavamail/internal/socks/socks5server/Socks5Handler.java similarity index 87% rename from src/main/java/org/codemonkey/simplejavamail/internal/socks/socks5server/Socks5Handler.java rename to src/main/java/org/simplejavamail/internal/socks/socks5server/Socks5Handler.java index 0387a0f8b..dab2d5acb 100644 --- a/src/main/java/org/codemonkey/simplejavamail/internal/socks/socks5server/Socks5Handler.java +++ b/src/main/java/org/simplejavamail/internal/socks/socks5server/Socks5Handler.java @@ -1,12 +1,12 @@ -package org.codemonkey.simplejavamail.internal.socks.socks5server; - -import org.codemonkey.simplejavamail.internal.socks.common.Socks5Bridge; -import org.codemonkey.simplejavamail.internal.socks.common.SocksException; -import org.codemonkey.simplejavamail.internal.socks.socks5server.io.SocketPipe; -import org.codemonkey.simplejavamail.internal.socks.socks5server.msg.CommandMessage; -import org.codemonkey.simplejavamail.internal.socks.socks5server.msg.CommandResponseMessage; -import org.codemonkey.simplejavamail.internal.socks.socks5server.msg.MethodSelectionMessage; -import org.codemonkey.simplejavamail.internal.socks.socks5server.msg.ServerReply; +package org.simplejavamail.internal.socks.socks5server; + +import org.simplejavamail.internal.socks.common.Socks5Bridge; +import org.simplejavamail.internal.socks.common.SocksException; +import org.simplejavamail.internal.socks.socks5server.io.SocketPipe; +import org.simplejavamail.internal.socks.socks5server.msg.CommandMessage; +import org.simplejavamail.internal.socks.socks5server.msg.CommandResponseMessage; +import org.simplejavamail.internal.socks.socks5server.msg.MethodSelectionMessage; +import org.simplejavamail.internal.socks.socks5server.msg.ServerReply; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/src/main/java/org/codemonkey/simplejavamail/internal/socks/socks5server/SocksServerReplyException.java b/src/main/java/org/simplejavamail/internal/socks/socks5server/SocksServerReplyException.java similarity index 58% rename from src/main/java/org/codemonkey/simplejavamail/internal/socks/socks5server/SocksServerReplyException.java rename to src/main/java/org/simplejavamail/internal/socks/socks5server/SocksServerReplyException.java index 8e3db1185..cbc82cae3 100644 --- a/src/main/java/org/codemonkey/simplejavamail/internal/socks/socks5server/SocksServerReplyException.java +++ b/src/main/java/org/simplejavamail/internal/socks/socks5server/SocksServerReplyException.java @@ -1,7 +1,7 @@ -package org.codemonkey.simplejavamail.internal.socks.socks5server; +package org.simplejavamail.internal.socks.socks5server; -import org.codemonkey.simplejavamail.internal.socks.common.SocksException; -import org.codemonkey.simplejavamail.internal.socks.socks5server.msg.ServerReply; +import org.simplejavamail.internal.socks.common.SocksException; +import org.simplejavamail.internal.socks.socks5server.msg.ServerReply; public class SocksServerReplyException extends SocksException { diff --git a/src/main/java/org/codemonkey/simplejavamail/internal/socks/socks5server/SocksSession.java b/src/main/java/org/simplejavamail/internal/socks/socks5server/SocksSession.java similarity index 96% rename from src/main/java/org/codemonkey/simplejavamail/internal/socks/socks5server/SocksSession.java rename to src/main/java/org/simplejavamail/internal/socks/socks5server/SocksSession.java index 9149cdf00..f1a839722 100644 --- a/src/main/java/org/codemonkey/simplejavamail/internal/socks/socks5server/SocksSession.java +++ b/src/main/java/org/simplejavamail/internal/socks/socks5server/SocksSession.java @@ -1,4 +1,4 @@ -package org.codemonkey.simplejavamail.internal.socks.socks5server; +package org.simplejavamail.internal.socks.socks5server; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/src/main/java/org/codemonkey/simplejavamail/internal/socks/socks5server/StreamUtil.java b/src/main/java/org/simplejavamail/internal/socks/socks5server/StreamUtil.java similarity index 74% rename from src/main/java/org/codemonkey/simplejavamail/internal/socks/socks5server/StreamUtil.java rename to src/main/java/org/simplejavamail/internal/socks/socks5server/StreamUtil.java index a4831e12a..86113ff33 100644 --- a/src/main/java/org/codemonkey/simplejavamail/internal/socks/socks5server/StreamUtil.java +++ b/src/main/java/org/simplejavamail/internal/socks/socks5server/StreamUtil.java @@ -1,4 +1,4 @@ -package org.codemonkey.simplejavamail.internal.socks.socks5server; +package org.simplejavamail.internal.socks.socks5server; import java.io.IOException; diff --git a/src/main/java/org/codemonkey/simplejavamail/internal/socks/socks5server/io/SocketPipe.java b/src/main/java/org/simplejavamail/internal/socks/socks5server/io/SocketPipe.java similarity index 96% rename from src/main/java/org/codemonkey/simplejavamail/internal/socks/socks5server/io/SocketPipe.java rename to src/main/java/org/simplejavamail/internal/socks/socks5server/io/SocketPipe.java index 9267101a2..fd4467069 100644 --- a/src/main/java/org/codemonkey/simplejavamail/internal/socks/socks5server/io/SocketPipe.java +++ b/src/main/java/org/simplejavamail/internal/socks/socks5server/io/SocketPipe.java @@ -1,4 +1,4 @@ -package org.codemonkey.simplejavamail.internal.socks.socks5server.io; +package org.simplejavamail.internal.socks.socks5server.io; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/src/main/java/org/codemonkey/simplejavamail/internal/socks/socks5server/io/StreamPipe.java b/src/main/java/org/simplejavamail/internal/socks/socks5server/io/StreamPipe.java similarity index 97% rename from src/main/java/org/codemonkey/simplejavamail/internal/socks/socks5server/io/StreamPipe.java rename to src/main/java/org/simplejavamail/internal/socks/socks5server/io/StreamPipe.java index 81a49e766..8cac381ff 100644 --- a/src/main/java/org/codemonkey/simplejavamail/internal/socks/socks5server/io/StreamPipe.java +++ b/src/main/java/org/simplejavamail/internal/socks/socks5server/io/StreamPipe.java @@ -1,4 +1,4 @@ -package org.codemonkey.simplejavamail.internal.socks.socks5server.io; +package org.simplejavamail.internal.socks.socks5server.io; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/src/main/java/org/codemonkey/simplejavamail/internal/socks/socks5server/msg/CommandMessage.java b/src/main/java/org/simplejavamail/internal/socks/socks5server/msg/CommandMessage.java similarity index 86% rename from src/main/java/org/codemonkey/simplejavamail/internal/socks/socks5server/msg/CommandMessage.java rename to src/main/java/org/simplejavamail/internal/socks/socks5server/msg/CommandMessage.java index 9b51764e1..11956611d 100644 --- a/src/main/java/org/codemonkey/simplejavamail/internal/socks/socks5server/msg/CommandMessage.java +++ b/src/main/java/org/simplejavamail/internal/socks/socks5server/msg/CommandMessage.java @@ -1,8 +1,8 @@ -package org.codemonkey.simplejavamail.internal.socks.socks5server.msg; +package org.simplejavamail.internal.socks.socks5server.msg; -import org.codemonkey.simplejavamail.internal.socks.common.SocksException; -import org.codemonkey.simplejavamail.internal.socks.socks5server.AddressType; -import org.codemonkey.simplejavamail.internal.socks.socks5server.SocksServerReplyException; +import org.simplejavamail.internal.socks.common.SocksException; +import org.simplejavamail.internal.socks.socks5server.AddressType; +import org.simplejavamail.internal.socks.socks5server.SocksServerReplyException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -12,7 +12,7 @@ import java.net.UnknownHostException; import static java.nio.charset.StandardCharsets.UTF_8; -import static org.codemonkey.simplejavamail.internal.socks.socks5server.StreamUtil.checkEnd; +import static org.simplejavamail.internal.socks.socks5server.StreamUtil.checkEnd; public class CommandMessage { diff --git a/src/main/java/org/codemonkey/simplejavamail/internal/socks/socks5server/msg/CommandResponseMessage.java b/src/main/java/org/simplejavamail/internal/socks/socks5server/msg/CommandResponseMessage.java similarity index 88% rename from src/main/java/org/codemonkey/simplejavamail/internal/socks/socks5server/msg/CommandResponseMessage.java rename to src/main/java/org/simplejavamail/internal/socks/socks5server/msg/CommandResponseMessage.java index e2e516eeb..4b854ca55 100644 --- a/src/main/java/org/codemonkey/simplejavamail/internal/socks/socks5server/msg/CommandResponseMessage.java +++ b/src/main/java/org/simplejavamail/internal/socks/socks5server/msg/CommandResponseMessage.java @@ -1,5 +1,6 @@ -package org.codemonkey.simplejavamail.internal.socks.socks5server.msg; +package org.simplejavamail.internal.socks.socks5server.msg; +import org.simplejavamail.internal.socks.socks5server.Socks5Handler; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -16,7 +17,7 @@ public static byte[] getBytes(ServerReply reply) { public static byte[] getBytes(ServerReply reply, InetAddress bindAddress, int bindPort) { int addressType = (bindAddress.getAddress().length == 4) ? 0x01 : 0x0; - int version = org.codemonkey.simplejavamail.internal.socks.socks5server.Socks5Handler.VERSION; + int version = Socks5Handler.VERSION; final byte[] bytes = new byte[10]; diff --git a/src/main/java/org/codemonkey/simplejavamail/internal/socks/socks5server/msg/MethodSelectionMessage.java b/src/main/java/org/simplejavamail/internal/socks/socks5server/msg/MethodSelectionMessage.java similarity index 78% rename from src/main/java/org/codemonkey/simplejavamail/internal/socks/socks5server/msg/MethodSelectionMessage.java rename to src/main/java/org/simplejavamail/internal/socks/socks5server/msg/MethodSelectionMessage.java index 4151b2087..886572643 100644 --- a/src/main/java/org/codemonkey/simplejavamail/internal/socks/socks5server/msg/MethodSelectionMessage.java +++ b/src/main/java/org/simplejavamail/internal/socks/socks5server/msg/MethodSelectionMessage.java @@ -1,4 +1,4 @@ -package org.codemonkey.simplejavamail.internal.socks.socks5server.msg; +package org.simplejavamail.internal.socks.socks5server.msg; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -6,7 +6,7 @@ import java.io.IOException; import java.io.InputStream; -import static org.codemonkey.simplejavamail.internal.socks.socks5server.StreamUtil.checkEnd; +import static org.simplejavamail.internal.socks.socks5server.StreamUtil.checkEnd; public class MethodSelectionMessage { diff --git a/src/main/java/org/codemonkey/simplejavamail/internal/socks/socks5server/msg/ServerReply.java b/src/main/java/org/simplejavamail/internal/socks/socks5server/msg/ServerReply.java similarity index 91% rename from src/main/java/org/codemonkey/simplejavamail/internal/socks/socks5server/msg/ServerReply.java rename to src/main/java/org/simplejavamail/internal/socks/socks5server/msg/ServerReply.java index a664a1caf..b00f5f525 100644 --- a/src/main/java/org/codemonkey/simplejavamail/internal/socks/socks5server/msg/ServerReply.java +++ b/src/main/java/org/simplejavamail/internal/socks/socks5server/msg/ServerReply.java @@ -1,4 +1,4 @@ -package org.codemonkey.simplejavamail.internal.socks.socks5server.msg; +package org.simplejavamail.internal.socks.socks5server.msg; /** * The enumeration ServerReply represents reply of servers will SOCKS client send a command request to the SOCKS server. diff --git a/src/main/java/org/codemonkey/simplejavamail/util/MimeMessageParser.java b/src/main/java/org/simplejavamail/util/MimeMessageParser.java similarity index 99% rename from src/main/java/org/codemonkey/simplejavamail/util/MimeMessageParser.java rename to src/main/java/org/simplejavamail/util/MimeMessageParser.java index 081361610..621884618 100644 --- a/src/main/java/org/codemonkey/simplejavamail/util/MimeMessageParser.java +++ b/src/main/java/org/simplejavamail/util/MimeMessageParser.java @@ -15,7 +15,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.codemonkey.simplejavamail.util; +package org.simplejavamail.util; import javax.activation.DataHandler; import javax.activation.DataSource; diff --git a/src/test/java/demo/MailTestApp.java b/src/test/java/demo/MailTestApp.java index b558d84d0..df802fda7 100644 --- a/src/test/java/demo/MailTestApp.java +++ b/src/test/java/demo/MailTestApp.java @@ -1,9 +1,9 @@ package demo; -import org.codemonkey.simplejavamail.Mailer; -import org.codemonkey.simplejavamail.ServerConfig; -import org.codemonkey.simplejavamail.TransportStrategy; -import org.codemonkey.simplejavamail.email.Email; +import org.simplejavamail.Mailer; +import org.simplejavamail.ServerConfig; +import org.simplejavamail.TransportStrategy; +import org.simplejavamail.email.Email; import javax.mail.Message.RecipientType; import javax.mail.MessagingException; diff --git a/src/test/java/org/codemonkey/simplejavamail/MailerTest.java b/src/test/java/org/simplejavamail/MailerTest.java similarity index 92% rename from src/test/java/org/codemonkey/simplejavamail/MailerTest.java rename to src/test/java/org/simplejavamail/MailerTest.java index 6566c3321..8d29f1f3c 100644 --- a/src/test/java/org/codemonkey/simplejavamail/MailerTest.java +++ b/src/test/java/org/simplejavamail/MailerTest.java @@ -1,7 +1,7 @@ -package org.codemonkey.simplejavamail; +package org.simplejavamail; -import org.codemonkey.simplejavamail.email.Email; -import org.codemonkey.simplejavamail.email.EmailTest; +import org.simplejavamail.email.Email; +import org.simplejavamail.email.EmailTest; import org.junit.Test; import javax.mail.MessagingException; diff --git a/src/test/java/org/codemonkey/simplejavamail/email/EmailTest.java b/src/test/java/org/simplejavamail/email/EmailTest.java similarity index 97% rename from src/test/java/org/codemonkey/simplejavamail/email/EmailTest.java rename to src/test/java/org/simplejavamail/email/EmailTest.java index 4681ad6e8..f9bd3f099 100644 --- a/src/test/java/org/codemonkey/simplejavamail/email/EmailTest.java +++ b/src/test/java/org/simplejavamail/email/EmailTest.java @@ -1,6 +1,6 @@ -package org.codemonkey.simplejavamail.email; +package org.simplejavamail.email; -import org.codemonkey.simplejavamail.Mailer; +import org.simplejavamail.Mailer; import org.junit.Test; import javax.mail.Message;