This is an automated email from the ASF dual-hosted git repository.
exceptionfactory pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/nifi.git
The following commit(s) were added to refs/heads/main by this push:
new cb0753b03c NIFI-9758 Added Dynamic Properties to PutEmail
cb0753b03c is described below
commit cb0753b03cc7fe55b86cc795d9b7cd328c783fc0
Author: Emilio Setiadarma <[email protected]>
AuthorDate: Tue Jul 12 16:48:37 2022 -0700
NIFI-9758 Added Dynamic Properties to PutEmail
This closes #6204
Signed-off-by: David Handermann <[email protected]>
---
.../apache/nifi/processors/standard/PutEmail.java | 71 +++++++++++++++++++++-
.../nifi/processors/standard/TestPutEmail.java | 56 ++++++++++++-----
2 files changed, 110 insertions(+), 17 deletions(-)
diff --git
a/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/main/java/org/apache/nifi/processors/standard/PutEmail.java
b/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/main/java/org/apache/nifi/processors/standard/PutEmail.java
index c083f26abe..1f35e50cd9 100644
---
a/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/main/java/org/apache/nifi/processors/standard/PutEmail.java
+++
b/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/main/java/org/apache/nifi/processors/standard/PutEmail.java
@@ -31,6 +31,7 @@ import java.util.Map;
import java.util.Map.Entry;
import java.util.Properties;
import java.util.Set;
+import java.util.regex.Matcher;
import java.util.regex.Pattern;
import jakarta.activation.DataHandler;
@@ -51,9 +52,11 @@ import jakarta.mail.internet.PreencodedMimeBodyPart;
import jakarta.mail.util.ByteArrayDataSource;
import org.apache.commons.codec.binary.Base64;
+import org.apache.nifi.annotation.behavior.DynamicProperty;
import org.apache.nifi.annotation.behavior.InputRequirement;
import org.apache.nifi.annotation.behavior.InputRequirement.Requirement;
import org.apache.nifi.annotation.behavior.SupportsBatching;
+import org.apache.nifi.annotation.behavior.SupportsSensitiveDynamicProperties;
import org.apache.nifi.annotation.behavior.SystemResource;
import org.apache.nifi.annotation.behavior.SystemResourceConsideration;
import org.apache.nifi.annotation.documentation.CapabilityDescription;
@@ -62,6 +65,7 @@ import org.apache.nifi.annotation.lifecycle.OnScheduled;
import org.apache.nifi.components.PropertyDescriptor;
import org.apache.nifi.components.ValidationContext;
import org.apache.nifi.components.ValidationResult;
+import org.apache.nifi.components.Validator;
import org.apache.nifi.expression.ExpressionLanguageScope;
import org.apache.nifi.flowfile.FlowFile;
import org.apache.nifi.flowfile.attributes.CoreAttributes;
@@ -79,10 +83,18 @@ import org.apache.nifi.stream.io.StreamUtils;
@Tags({"email", "put", "notify", "smtp"})
@InputRequirement(Requirement.INPUT_REQUIRED)
@CapabilityDescription("Sends an e-mail to configured recipients for each
incoming FlowFile")
+@SupportsSensitiveDynamicProperties
+@DynamicProperty(name = "mail.propertyName",
+ value = "Value for a specific property to be set in the JavaMail
Session object",
+ description = "Dynamic property names that will be passed to the Mail
session. " +
+ "Possible properties can be found in:
https://javaee.github.io/javamail/docs/api/com/sun/mail/smtp/package-summary.html.",
+ expressionLanguageScope = ExpressionLanguageScope.FLOWFILE_ATTRIBUTES)
@SystemResourceConsideration(resource = SystemResource.MEMORY, description =
"The entirety of the FlowFile's content (as a String object) "
+ "will be read into memory in case the property to use the flow file
content as the email body is set to true.")
public class PutEmail extends AbstractProcessor {
+ private static final Pattern MAIL_PROPERTY_PATTERN =
Pattern.compile("^mail\\.smtps?\\.([a-z0-9\\.]+)$");
+
public static final PropertyDescriptor SMTP_HOSTNAME = new
PropertyDescriptor.Builder()
.name("SMTP Hostname")
.description("The hostname of the SMTP host")
@@ -150,8 +162,8 @@ public class PutEmail extends AbstractProcessor {
.name("attribute-name-regex")
.displayName("Attributes to Send as Headers (Regex)")
.description("A Regular Expression that is matched against all
FlowFile attribute names. "
- + "Any attribute whose name matches the regex will be added to
the Email messages as a Header. "
- + "If not specified, no FlowFile attributes will be added as
headers.")
+ + "Any attribute whose name matches the regex will be
added to the Email messages as a Header. "
+ + "If not specified, no FlowFile attributes will be added
as headers.")
.addValidator(StandardValidators.REGULAR_EXPRESSION_VALIDATOR)
.required(false)
.build();
@@ -305,6 +317,18 @@ public class PutEmail extends AbstractProcessor {
return properties;
}
+ @Override
+ protected PropertyDescriptor getSupportedDynamicPropertyDescriptor(final
String propertyDescriptorName) {
+ return new PropertyDescriptor.Builder()
+ .name(propertyDescriptorName)
+ .description("SMTP property passed to the Mail Session")
+ .required(false)
+ .dynamic(true)
+
.expressionLanguageSupported(ExpressionLanguageScope.FLOWFILE_ATTRIBUTES)
+ .addValidator(new DynamicMailPropertyValidator())
+ .build();
+ }
+
@Override
protected Collection<ValidationResult> customValidate(final
ValidationContext context) {
final List<ValidationResult> errors = new
ArrayList<>(super.customValidate(context));
@@ -464,6 +488,16 @@ public class PutEmail extends AbstractProcessor {
}
}
+ for (final PropertyDescriptor descriptor :
context.getProperties().keySet()) {
+ if (descriptor.isDynamic()) {
+ final String mailPropertyValue =
context.getProperty(descriptor).evaluateAttributeExpressions(flowFile).getValue();
+ // Nullable values are not allowed, so filter out
+ if (null != mailPropertyValue) {
+ properties.setProperty(descriptor.getName(),
mailPropertyValue);
+ }
+ }
+ }
+
return properties;
}
@@ -493,7 +527,7 @@ public class PutEmail extends AbstractProcessor {
* @throws AddressException if the property cannot be parsed to a valid
InternetAddress[]
*/
private InternetAddress[] toInetAddresses(final ProcessContext context,
final FlowFile flowFile,
- PropertyDescriptor propertyDescriptor) throws AddressException {
+ PropertyDescriptor
propertyDescriptor) throws AddressException {
InternetAddress[] parse;
final String value =
context.getProperty(propertyDescriptor).evaluateAttributeExpressions(flowFile).getValue();
if (value == null || value.isEmpty()){
@@ -523,4 +557,35 @@ public class PutEmail extends AbstractProcessor {
protected void send(final Message msg) throws MessagingException {
Transport.send(msg);
}
+
+ private static class DynamicMailPropertyValidator implements Validator {
+ @Override
+ public ValidationResult validate(String subject, String input,
ValidationContext context) {
+ final Matcher matcher = MAIL_PROPERTY_PATTERN.matcher(subject);
+ if (!matcher.matches()) {
+ return new ValidationResult.Builder()
+ .input(input)
+ .subject(subject)
+ .valid(false)
+ .explanation(String.format("[%s] does not start with
mail.smtp", subject))
+ .build();
+ }
+
+ if (propertyToContext.containsKey(subject)) {
+ return new ValidationResult.Builder()
+ .input(input)
+ .subject(subject)
+ .valid(false)
+ .explanation(String.format("[%s] overwrites standard
properties", subject))
+ .build();
+ }
+
+ return new ValidationResult.Builder()
+ .subject(subject)
+ .input(input)
+ .valid(true)
+ .explanation("Valid mail.smtp property found")
+ .build();
+ }
+ }
}
diff --git
a/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/test/java/org/apache/nifi/processors/standard/TestPutEmail.java
b/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/test/java/org/apache/nifi/processors/standard/TestPutEmail.java
index 7c18570bcf..464526d2e1 100644
---
a/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/test/java/org/apache/nifi/processors/standard/TestPutEmail.java
+++
b/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/test/java/org/apache/nifi/processors/standard/TestPutEmail.java
@@ -180,11 +180,9 @@ public class TestPutEmail {
@Test
public void testInvalidAddress() {
// verifies that unparsable addresses lead to the flow file being
routed to failure
- runner.setProperty(PutEmail.SMTP_HOSTNAME, "smtp-host");
- runner.setProperty(PutEmail.HEADER_XMAILER, "TestingNiFi");
+ setRequiredProperties(runner);
runner.setProperty(PutEmail.FROM, "[email protected] <invalid");
runner.setProperty(PutEmail.MESSAGE, "Message Body");
- runner.setProperty(PutEmail.TO, "[email protected]");
runner.enqueue("Some Text".getBytes());
@@ -200,11 +198,9 @@ public class TestPutEmail {
public void testEmptyFrom() {
// verifies that if the FROM property evaluates to an empty string at
// runtime the flow file is transferred to failure.
- runner.setProperty(PutEmail.SMTP_HOSTNAME, "smtp-host");
- runner.setProperty(PutEmail.HEADER_XMAILER, "TestingNiFi");
+ setRequiredProperties(runner);
runner.setProperty(PutEmail.FROM, "${MISSING_PROPERTY}");
runner.setProperty(PutEmail.MESSAGE, "Message Body");
- runner.setProperty(PutEmail.TO, "[email protected]");
runner.enqueue("Some Text".getBytes());
@@ -220,13 +216,10 @@ public class TestPutEmail {
@Test
public void testOutgoingMessageAttachment() throws Exception {
// verifies that are set on the outgoing Message correctly
- runner.setProperty(PutEmail.SMTP_HOSTNAME, "smtp-host");
- runner.setProperty(PutEmail.HEADER_XMAILER, "TestingNiFi");
- runner.setProperty(PutEmail.FROM, "[email protected]");
+ setRequiredProperties(runner);
runner.setProperty(PutEmail.MESSAGE, "Message Body");
runner.setProperty(PutEmail.ATTACH_FILE, "true");
runner.setProperty(PutEmail.CONTENT_TYPE, "text/html");
- runner.setProperty(PutEmail.TO, "[email protected]");
Map<String, String> attributes = new HashMap<>();
attributes.put(CoreAttributes.FILENAME.key(), "test한的ほу́.pdf");
@@ -265,11 +258,8 @@ public class TestPutEmail {
@Test
public void testOutgoingMessageWithFlowfileContent() throws Exception {
// verifies that are set on the outgoing Message correctly
- runner.setProperty(PutEmail.SMTP_HOSTNAME, "smtp-host");
- runner.setProperty(PutEmail.HEADER_XMAILER, "TestingNiFi");
- runner.setProperty(PutEmail.FROM, "[email protected],[email protected]");
+ setRequiredProperties(runner);
runner.setProperty(PutEmail.MESSAGE, "${body}");
- runner.setProperty(PutEmail.TO,
"[email protected],[email protected]");
runner.setProperty(PutEmail.CC,
"[email protected],[email protected]");
runner.setProperty(PutEmail.BCC,
"[email protected],[email protected]");
runner.setProperty(PutEmail.CONTENT_AS_MESSAGE, "${sendContent}");
@@ -299,4 +289,42 @@ public class TestPutEmail {
assertEquals("[email protected]",
message.getRecipients(RecipientType.BCC)[1].toString());
}
+ @Test
+ public void testValidDynamicMailProperties() {
+ setRequiredProperties(runner);
+ runner.setProperty(PutEmail.MESSAGE, "${body}");
+ runner.setProperty(PutEmail.CONTENT_AS_MESSAGE, "${sendContent}");
+
+ runner.setProperty("mail.smtp.timeout", "sample dynamic smtp
property");
+ runner.setProperty("mail.smtps.timeout", "sample dynamic smtps
property");
+ runner.assertValid();
+ }
+
+ @Test
+ public void testInvalidDynamicMailPropertyName() {
+ setRequiredProperties(runner);
+ runner.setProperty(PutEmail.MESSAGE, "${body}");
+ runner.setProperty(PutEmail.CONTENT_AS_MESSAGE, "${sendContent}");
+
+ runner.setProperty("mail.", "sample_value");
+ runner.assertNotValid();
+ }
+
+ @Test
+ public void testOverwritingDynamicMailProperty() {
+ setRequiredProperties(runner);
+ runner.setProperty(PutEmail.MESSAGE, "${body}");
+ runner.setProperty(PutEmail.CONTENT_AS_MESSAGE, "${sendContent}");
+
+ runner.setProperty("mail.smtp.user", "test-user-value");
+ runner.assertNotValid();
+ }
+
+ private void setRequiredProperties(final TestRunner runner) {
+ // values here may be overridden in some tests
+ runner.setProperty(PutEmail.SMTP_HOSTNAME, "smtp-host");
+ runner.setProperty(PutEmail.HEADER_XMAILER, "TestingNiFi");
+ runner.setProperty(PutEmail.FROM, "[email protected],[email protected]");
+ runner.setProperty(PutEmail.TO,
"[email protected],[email protected]");
+ }
}