Skip to content

Commit

Permalink
#447: Added value-defaulting control for individual properties, to ma…
Browse files Browse the repository at this point in the history
…ke sure they don't get a default value

#447: Added value-overriding control for individual properties, to make sure they don't get overridden
#297: Streamlined how defaults/overrides are determined by EmailGovernance and MiscUtil
#297: Removed the signByDefault methods from Mailer; signWithSmime on Email already works on for the defaults Email reference
#446: Added missing config properties for DKIM
  • Loading branch information
bbottema committed Feb 26, 2023
1 parent 619a910 commit c1b266d
Show file tree
Hide file tree
Showing 25 changed files with 589 additions and 379 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import org.simplejavamail.api.email.config.DkimConfig;
import org.simplejavamail.api.internal.smimesupport.model.PlainSmimeDetails;
import org.simplejavamail.api.mailer.config.Pkcs12Config;
import org.simplejavamail.internal.config.EmailProperty;
import org.simplejavamail.internal.util.MiscUtil;

import java.io.InputStream;
Expand Down Expand Up @@ -40,6 +41,16 @@ public class Email implements Serializable {

private static final long serialVersionUID = 1234567L;

/**
* @see EmailPopulatingBuilder#dontApplyDefaultValueFor(EmailProperty...)
*/
private final Set<EmailProperty> propertiesNotToApplyDefaultValueFor;

/**
* @see EmailPopulatingBuilder#dontApplyOverrideValueFor(EmailProperty...)
*/
private final Set<EmailProperty> propertiesNotToApplyOverrideValueFor;

/**
* @see EmailPopulatingBuilder#fixingMessageId(String)
*/
Expand Down Expand Up @@ -207,6 +218,8 @@ public class Email implements Serializable {
public Email(@NotNull final EmailPopulatingBuilder builder) {
checkNonEmptyArgument(builder, "builder");

propertiesNotToApplyDefaultValueFor = builder.getPropertiesNotToApplyDefaultValueFor();
propertiesNotToApplyOverrideValueFor = builder.getPropertiesNotToApplyOverrideValueFor();
smimeSignedEmail = builder.getSmimeSignedEmail();

final boolean smimeMerge = builder.isMergeSingleSMIMESignedAttachment() && smimeSignedEmail != null;
Expand Down Expand Up @@ -375,6 +388,22 @@ private String formatDate(@Nullable Date date) {
return sdf.format(date);
}

/**
* @see EmailPopulatingBuilder#dontApplyDefaultValueFor(EmailProperty...)
*/
@Nullable
public Set<EmailProperty> getPropertiesNotToApplyDefaultValueFor() {
return propertiesNotToApplyDefaultValueFor;
}

/**
* @see EmailPopulatingBuilder#dontApplyOverrideValueFor(EmailProperty...)
*/
@Nullable
public Set<EmailProperty> getPropertiesNotToApplyOverrideValueFor() {
return propertiesNotToApplyOverrideValueFor;
}

/**
* @see EmailPopulatingBuilder#fixingMessageId(String)
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
import org.simplejavamail.api.internal.clisupport.model.Cli;
import org.simplejavamail.api.internal.clisupport.model.CliBuilderApiType;
import org.simplejavamail.api.mailer.config.Pkcs12Config;
import org.simplejavamail.internal.config.EmailProperty;

import java.io.File;
import java.io.InputStream;
Expand Down Expand Up @@ -47,6 +48,28 @@ public interface EmailPopulatingBuilder {
*/
@Cli.ExcludeApi(reason = "This API is specifically for Java use")
Email buildEmail();

/**
* Allows you to prevent a property to be configured with default values. This might be useful if you have defined defaults (either through (system) properties,
* config files, or on mailer level on the {@link org.simplejavamail.api.mailer.config.EmailGovernance}), but for a specific case or under certain conditions
* you might want to have this email untouched by the defaults.
* <br>
* <strong>Note:</strong> This is irrelevant for Email instances used to set on {@link org.simplejavamail.api.mailer.config.EmailGovernance}
* as defaults or overrides reference.
*
* @param configProperties The properties that should not be configured with default values, if any, when sending the email.
* @see EmailStartingBuilder#ignoringDefaults()
*/
EmailPopulatingBuilder dontApplyDefaultValueFor(@NotNull EmailProperty @NotNull ...configProperties);

/**
* Allows you to prevent a property to be configured with override values. This might be useful if you have defined overrides on mailer level on the
* {@link org.simplejavamail.api.mailer.config.EmailGovernance}), but for a specific case or under certain conditions you might want
* to have this email untouched by the overrides.
*
* @param configProperties The properties that should not be overridden when sending the email.
*/
EmailPopulatingBuilder dontApplyOverrideValueFor(@NotNull EmailProperty @NotNull ...configProperties);

/**
* Sets optional ID to a fixed value, which is otherwise generated by the underlying JavaMail framework when sending the email.
Expand Down Expand Up @@ -1174,7 +1197,6 @@ public interface EmailPopulatingBuilder {
*
* @see <a href="https://en.wikipedia.org/wiki/S/MIME">S/MIME on Wikipedia</a>
* @see <a href="https://www.globalsign.com/en/blog/what-is-s-mime/">Primer on S/MIME</a>
* @see org.simplejavamail.api.mailer.MailerGenericBuilder#signByDefaultWithSmime(Pkcs12Config)
*/
@Cli.ExcludeApi(reason = "delegated method contains CLI compatible arguments")
EmailPopulatingBuilder signWithSmime(@NotNull Pkcs12Config pkcs12Config);
Expand Down Expand Up @@ -1514,6 +1536,18 @@ public interface EmailPopulatingBuilder {
*/
EmailPopulatingBuilder clearSMIMESignedAttachmentMergingBehavior();

/**
* @see #dontApplyDefaultValueFor(EmailProperty...)
*/
@Nullable
Set<EmailProperty> getPropertiesNotToApplyDefaultValueFor();

/**
* @see #dontApplyOverrideValueFor(EmailProperty...)
*/
@Nullable
Set<EmailProperty> getPropertiesNotToApplyOverrideValueFor();

/**
* @see #fixingMessageId(String)
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import org.jetbrains.annotations.NotNull;
import org.simplejavamail.api.internal.clisupport.model.Cli;
import org.simplejavamail.api.internal.clisupport.model.CliBuilderApiType;
import org.simplejavamail.internal.config.EmailProperty;

import java.util.regex.Pattern;

Expand Down Expand Up @@ -36,7 +37,13 @@ public interface EmailStartingBuilder {
"1cm\">%s</blockquote>";

/**
* Configures this builder to create an email ignoring the normal (optional) defaults that apply from property config files.
* Configures this builder to create an email ignoring the all defaults from (System) properties, config files or defaults email on
* Mailer level in the {@link org.simplejavamail.api.mailer.config.EmailGovernance}.
* <br>
* <strong>Note:</strong> This is irrelevant for Email instances used to set on {@link org.simplejavamail.api.mailer.config.EmailGovernance}
* as defaults or overrides reference.
*
* @see EmailPopulatingBuilder#dontApplyDefaultValueFor(EmailProperty...)
*/
EmailStartingBuilder ignoringDefaults();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,8 @@
import org.simplejavamail.api.internal.clisupport.model.Cli;
import org.simplejavamail.api.internal.clisupport.model.CliBuilderApiType;
import org.simplejavamail.api.mailer.config.LoadBalancingStrategy;
import org.simplejavamail.api.mailer.config.Pkcs12Config;
import org.simplejavamail.api.mailer.config.TransportStrategy;

import java.io.File;
import java.io.InputStream;
import java.util.List;
import java.util.Map;
import java.util.Properties;
Expand Down Expand Up @@ -268,53 +265,6 @@ public interface MailerGenericBuilder<T extends MailerGenericBuilder<?>> {
*/
T withMaximumEmailSize(int maximumEmailSize);

/**
* Signs this <em>all emails by default</em> with an <a href="https://tools.ietf.org/html/rfc5751">S/MIME</a> signature, so the receiving client
* can verify whether the email content was tampered with.
* <p>
* <strong>Note:</strong> this only works in combination with the {@value org.simplejavamail.internal.modules.SMIMEModule#NAME}.
*
* @see <a href="https://en.wikipedia.org/wiki/S/MIME">S/MIME on Wikipedia</a>
* @see <a href="https://www.globalsign.com/en/blog/what-is-s-mime/">Primer on S/MIME</a>
* @see org.simplejavamail.api.email.EmailPopulatingBuilder#signWithSmime(Pkcs12Config)
* @see #clearSignByDefaultWithSmime()
*/
@Cli.ExcludeApi(reason = "delegated method contains CLI compatible arguments")
T signByDefaultWithSmime(@NotNull Pkcs12Config pkcs12Config);

/**
* Delegates to {@link #signByDefaultWithSmime(InputStream, String, String, String)}.
* <p>
* <strong>Note:</strong> this only works in combination with the {@value org.simplejavamail.internal.modules.SMIMEModule#NAME}.
*
* @param pkcs12StoreFile The key store file to use to find the indicated key
* @param storePassword The store's password
* @param keyAlias The name of the certificate in the key store to use
* @param keyPassword The password of the certificate
*/
T signByDefaultWithSmime(@NotNull File pkcs12StoreFile, @NotNull String storePassword, @NotNull String keyAlias, @NotNull String keyPassword);

/**
* Delegates to {@link #signByDefaultWithSmime(byte[], String, String, String)}.
* <p>
* <strong>Note:</strong> this only works in combination with the {@value org.simplejavamail.internal.modules.SMIMEModule#NAME}.
*/
@Cli.ExcludeApi(reason = "Is duplicate API from CLI point of view")
T signByDefaultWithSmime(@NotNull InputStream pkcs12StoreStream, @NotNull String storePassword, @NotNull String keyAlias, @NotNull String keyPassword);

/**
* Delegates to {@link #signByDefaultWithSmime(Pkcs12Config)}.
* <p>
* <strong>Note:</strong> this only works in combination with the {@value org.simplejavamail.internal.modules.SMIMEModule#NAME}.
*
* @param pkcs12StoreData The key store file to use to find the indicated key
* @param storePassword The store's password
* @param keyAlias The name of the certificate in the key store to use
* @param keyPassword The password of the certificate
*/
@Cli.ExcludeApi(reason = "Is duplicate API from CLI point of view")
T signByDefaultWithSmime(@NotNull byte[] pkcs12StoreData, @NotNull String storePassword, @NotNull String keyAlias, @NotNull String keyPassword);

/**
* <strong>For advanced use cases.</strong>
* <p>
Expand Down Expand Up @@ -700,13 +650,6 @@ public interface MailerGenericBuilder<T extends MailerGenericBuilder<?>> {
*/
T clearMaximumEmailSize();

/**
* Removes S/MIME signing, so emails won't be signed by default.
*
* @see #signByDefaultWithSmime(Pkcs12Config)
*/
T clearSignByDefaultWithSmime();

/**
* Removes all trusted hosts from the list.
*
Expand Down Expand Up @@ -801,13 +744,6 @@ public interface MailerGenericBuilder<T extends MailerGenericBuilder<?>> {
@Nullable
Integer getMaximumEmailSize();

/**
* @see #signByDefaultWithSmime(Pkcs12Config)
* @see #signByDefaultWithSmime(InputStream, String, String, String)
*/
@Nullable
Pkcs12Config getPkcs12ConfigForSmimeSigning();

/**
* Returns the user set ExecutorService or else null as the default ExecutorService is not created until the {@link org.simplejavamail.api.mailer.config.OperationalConfig} is created for the
* new {@link Mailer} instance.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,65 +1,58 @@
package org.simplejavamail.api.mailer.config;

import com.sanctionco.jmail.EmailValidator;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.ToString;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.simplejavamail.api.email.Email;
import org.simplejavamail.api.email.EmailPopulatingBuilder;
import org.simplejavamail.api.mailer.MailerGenericBuilder;
import org.simplejavamail.internal.config.EmailProperty;

import java.io.InputStream;
import java.util.Collection;
import java.util.List;
import java.util.Map;

/**
* Governance for all emails being sent through the current {@link org.simplejavamail.api.mailer.Mailer} instance. That is, this class represents actions
* taken or configuration used by default for each individual email sent through the current mailer. For example, you might want to S/MIME sign all emails
* by default. You <em>can</em> do it manually on each email of course, but then the keystore used for this is not reused.
* <p>
* Also, you can supply a custom {@link org.simplejavamail.api.email.Email email} instance which will be used for defaults. For example,
* you can set a default from address or subject.
* <p>
* You can set this on the {@code MailerBuilder} using {@code MailerBuilder.withEmailGovernance(EmailGovernance)}.
* Also, you can supply a custom {@link org.simplejavamail.api.email.Email email} instance which will be used for <em>defaults</em> or <em>overrides</em>. For example,
* you can set a default from address or subject. Any fields that are not set on the email will be taken from the defaults (properties). Any fields that are set on the
* email will be used instead of the defaults.
*/
@ToString
@AllArgsConstructor
@Getter()
public class EmailGovernance {

public static final EmailGovernance NO_GOVERNANCE = new EmailGovernance(null, null, null, null, null);

/**
* The effective email validator used for email validation. Can be <code>null</code> if no validation should be done.
* @see MailerGenericBuilder#withEmailValidator(EmailValidator)
* @see EmailValidator
*/
@Nullable private final EmailValidator emailValidator;

/**
* @see EmailPopulatingBuilder#signWithSmime(Pkcs12Config)
* @see EmailPopulatingBuilder#signWithSmime(InputStream, String, String, String)
* @see MailerGenericBuilder#signByDefaultWithSmime(Pkcs12Config)
* @see MailerGenericBuilder#signByDefaultWithSmime(InputStream, String, String, String)
*/
@Nullable private final Pkcs12Config pkcs12ConfigForSmimeSigning;

/**
* Reference email used for defaults if no fields are not filled in the email but are on this instance.
* Can be <code>null</code> if no defaults should be used.
* @see MailerGenericBuilder#withEmailDefaults(Email)
*/
@Nullable private final Email emailDefaults;

/**
* Reference email used for overrides. Values from this email will trump the incoming email.
* Can be <code>null</code> if no overrides should be used.
* @see MailerGenericBuilder#withEmailOverrides(Email)
*/
@Nullable private final Email emailOverrides;

/**
* Determines at what size Simple Java Mail should reject a MimeMessage. Useful if you know your SMTP server has a limit.
* @see MailerGenericBuilder#withMaximumEmailSize(int)
*/
@Nullable private final Integer maximumEmailSize;
public interface EmailGovernance {
/**
* @return The effective email validator used for email validation. Can be <code>null</code> if no validation should be done.
* @see MailerGenericBuilder#withEmailValidator(EmailValidator)
* @see EmailValidator
*/
@Nullable EmailValidator getEmailValidator();

/**
* @return Determines at what size Simple Java Mail should reject a MimeMessage. Useful if you know your SMTP server has a limit.
* @see MailerGenericBuilder#withMaximumEmailSize(int)
*/
@Nullable Integer getMaximumEmailSize();

/**
* Resolves a property by first checking overrides (if the override wasn't disabled globally, or for this property specifically), then checking the email itself, and finally
* checking the defaults (again checking if it was disabled). If the property is not set on any of these, <code>null</code> is returned.
*/
@Nullable <T> T resolveEmailProperty(@Nullable Email email, @NotNull EmailProperty emailProperty);

/**
* Resolves a collection property by first checking overrides (if the override wasn't disabled globally, or for this property specifically), then checking the email itself, and finally
* checking the defaults (again checking if it was disabled). If the property is not set on any of these, an empty <code>List</code> is returned.
* <br>
* The collections are merged from these sources, with the overrides taking precedence.
*/
@NotNull <T> List<T> resolveEmailCollectionProperty(@Nullable Email email, @NotNull EmailProperty emailProperty);

/**
* Specifically resolves the headers by first checking overrides (if the override wasn't disabled globally, or for this property specifically), then checking the email itself, and finally
* checking the defaults (again checking if it was disabled). If the property is not set on any of these, an empty <code>List</code> is returned.
* <br>
* The header maps are merged from these sources, with the overrides taking precedence. The keys are added to the map, but their associated value collections are not merged, but replaced.
*/
Map<String, Collection<String>> resolveEmailHeadersProperty(@Nullable Email email);
}
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,10 @@
* <li>simplejavamail.smime.signing.key_alias</li>
* <li>simplejavamail.smime.signing.key_password</li>
* <li>simplejavamail.smime.encryption.certificate</li>
* <li>simplejavamail.dkim.signing.private_key_file_or_data</li>
* <li>simplejavamail.dkim.signing.selector</li>
* <li>simplejavamail.dkim.signing.signing_domain</li>
* <li>simplejavamail.dkim.signing.excluded_headers_from_default_signing_list</li>
* <li>simplejavamail.embeddedimages.dynamicresolution.enable.dir</li>
* <li>simplejavamail.embeddedimages.dynamicresolution.enable.url</li>
* <li>simplejavamail.embeddedimages.dynamicresolution.enable.classpath</li>
Expand Down Expand Up @@ -171,6 +175,10 @@ public enum Property {
SMIME_SIGNING_KEYSTORE_PASSWORD("simplejavamail.smime.signing.keystore_password"),
SMIME_SIGNING_KEY_ALIAS("simplejavamail.smime.signing.key_alias"),
SMIME_SIGNING_KEY_PASSWORD("simplejavamail.smime.signing.key_password"),
DKIM_PRIVATE_KEY_FILE_OR_DATA("simplejavamail.dkim.signing.private_key_file_or_data"),
DKIM_SELECTOR("simplejavamail.dkim.signing.selector"),
DKIM_SIGNING_DOMAIN("simplejavamail.dkim.signing.signing_domain"),
DKIM_EXCLUDED_HEADERS_FROM_DEFAULT_SIGNING_LIST("simplejavamail.dkim.signing.excluded_headers_from_default_signing_list"),
SMIME_ENCRYPTION_CERTIFICATE("simplejavamail.smime.encryption.certificate"),
EMBEDDEDIMAGES_DYNAMICRESOLUTION_ENABLE_DIR("simplejavamail.embeddedimages.dynamicresolution.enable.dir"),
EMBEDDEDIMAGES_DYNAMICRESOLUTION_ENABLE_CLASSPATH("simplejavamail.embeddedimages.dynamicresolution.enable.classpath"),
Expand Down
Loading

0 comments on commit c1b266d

Please sign in to comment.