/*
* Copyright (c) 2010-2013 Evolveum
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.evolveum.midpoint.notifications.impl.api.transports;
import java.io.IOException;
import java.util.Date;
import java.util.Properties;
import javax.annotation.PostConstruct;
import javax.mail.MessagingException;
import javax.mail.Session;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import com.evolveum.midpoint.notifications.api.events.Event;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;
import com.evolveum.midpoint.notifications.api.NotificationManager;
import com.evolveum.midpoint.notifications.api.transports.Message;
import com.evolveum.midpoint.notifications.api.transports.Transport;
import com.evolveum.midpoint.notifications.impl.NotificationFunctionsImpl;
import com.evolveum.midpoint.prism.crypto.EncryptionException;
import com.evolveum.midpoint.prism.crypto.Protector;
import com.evolveum.midpoint.repo.api.RepositoryService;
import com.evolveum.midpoint.schema.result.OperationResult;
import com.evolveum.midpoint.task.api.Task;
import com.evolveum.midpoint.util.logging.LoggingUtils;
import com.evolveum.midpoint.util.logging.Trace;
import com.evolveum.midpoint.util.logging.TraceManager;
import com.evolveum.midpoint.xml.ns._public.common.common_3.MailConfigurationType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.MailServerConfigurationType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.MailTransportSecurityType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.SystemConfigurationType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.UserType;
import com.evolveum.prism.xml.ns._public.types_3.ProtectedStringType;
/**
* @author mederly
*/
@Component
public class MailTransport implements Transport {
private static final Trace LOGGER = TraceManager.getTrace(MailTransport.class);
private static final String NAME = "mail";
private static final String DOT_CLASS = MailTransport.class.getName() + ".";
@Autowired
@Qualifier("cacheRepositoryService")
private transient RepositoryService cacheRepositoryService;
@Autowired
private Protector protector;
@Autowired
private NotificationManager notificationManager;
@PostConstruct
public void init() {
notificationManager.registerTransport(NAME, this);
}
@Override
public void send(Message mailMessage, String transportName, Event event, Task task, OperationResult parentResult) {
OperationResult result = parentResult.createSubresult(DOT_CLASS + "send");
result.addCollectionOfSerializablesAsParam("mailMessage recipient(s)", mailMessage.getTo());
result.addParam("mailMessage subject", mailMessage.getSubject());
SystemConfigurationType systemConfiguration = NotificationFunctionsImpl.getSystemConfiguration(cacheRepositoryService, new OperationResult("dummy"));
// if (systemConfiguration == null) {
// String msg = "No notifications are configured. Mail notification to " + mailMessage.getTo() + " will not be sent.";
// LOGGER.warn(msg) ;
// result.recordWarning(msg);
// return;
// }
//
// MailConfigurationType mailConfigurationType = null;
// SecurityPolicyType securityPolicyType = NotificationFuctionsImpl.getSecurityPolicyConfiguration(systemConfiguration.getGlobalSecurityPolicyRef(), cacheRepositoryService, result);
// if (securityPolicyType != null && securityPolicyType.getAuthentication() != null && securityPolicyType.getAuthentication().getMailAuthentication() != null) {
// for (MailAuthenticationPolicyType mailAuthenticationPolicy : securityPolicyType.getAuthentication().getMailAuthentication()) {
// if (mailAuthenticationPolicy.getNotificationConfiguration() != null ){
// mailConfigurationType = mailAuthenticationPolicy.getNotificationConfiguration().getMail();
// }
// }
// }
if (systemConfiguration == null || systemConfiguration.getNotificationConfiguration() == null
|| systemConfiguration.getNotificationConfiguration().getMail() == null) {
String msg = "No notifications are configured. Mail notification to " + mailMessage.getTo() + " will not be sent.";
LOGGER.warn(msg) ;
result.recordWarning(msg);
return;
}
// if (mailConfigurationType == null) {
MailConfigurationType mailConfigurationType = systemConfiguration.getNotificationConfiguration().getMail();
// }
String redirectToFile = mailConfigurationType.getRedirectToFile();
if (redirectToFile != null) {
try {
TransportUtil.appendToFile(redirectToFile, formatToFile(mailMessage));
result.recordSuccess();
} catch (IOException e) {
LoggingUtils.logException(LOGGER, "Couldn't write to mail redirect file {}", e, redirectToFile);
result.recordPartialError("Couldn't write to mail redirect file " + redirectToFile, e);
}
return;
}
if (mailConfigurationType.getServer().isEmpty()) {
String msg = "Mail server(s) are not defined, mail notification to " + mailMessage.getTo() + " will not be sent.";
LOGGER.warn(msg) ;
result.recordWarning(msg);
return;
}
long start = System.currentTimeMillis();
String defaultFrom = mailConfigurationType.getDefaultFrom() != null ? mailConfigurationType.getDefaultFrom() : "nobody@nowhere.org";
for (MailServerConfigurationType mailServerConfigurationType : mailConfigurationType.getServer()) {
OperationResult resultForServer = result.createSubresult(DOT_CLASS + "send.forServer");
final String host = mailServerConfigurationType.getHost();
resultForServer.addContext("server", host);
resultForServer.addContext("port", mailServerConfigurationType.getPort());
Properties properties = System.getProperties();
properties.setProperty("mail.smtp.host", host);
if (mailServerConfigurationType.getPort() != null) {
properties.setProperty("mail.smtp.port", String.valueOf(mailServerConfigurationType.getPort()));
}
MailTransportSecurityType mailTransportSecurityType = mailServerConfigurationType.getTransportSecurity();
boolean sslEnabled = false, starttlsEnable = false, starttlsRequired = false;
if (mailTransportSecurityType != null) {
switch (mailTransportSecurityType) {
case STARTTLS_ENABLED:
starttlsEnable = true;
break;
case STARTTLS_REQUIRED:
starttlsEnable = true;
starttlsRequired = true;
break;
case SSL:
sslEnabled = true;
break;
}
}
properties.put("mail.smtp.ssl.enable", "" + sslEnabled);
properties.put("mail.smtp.starttls.enable", "" + starttlsEnable);
properties.put("mail.smtp.starttls.required", "" + starttlsRequired);
if (Boolean.TRUE.equals(mailConfigurationType.isDebug())) {
properties.put("mail.debug", "true");
}
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Using mail properties: ");
for (Object key : properties.keySet()) {
if (key instanceof String && ((String) key).startsWith("mail.")) {
LOGGER.debug(" - " + key + " = " + properties.get(key));
}
}
}
task.recordState("Sending notification mail via " + host);
Session session = Session.getInstance(properties);
try {
MimeMessage mimeMessage = new MimeMessage(session);
String from = mailMessage.getFrom() != null ? mailMessage.getFrom() : defaultFrom;
mimeMessage.setFrom(new InternetAddress(from));
for (String recipient : mailMessage.getTo()) {
mimeMessage.addRecipient(javax.mail.Message.RecipientType.TO, new InternetAddress(recipient));
}
for (String recipientCc : mailMessage.getCc()) {
mimeMessage.addRecipient(javax.mail.Message.RecipientType.CC, new InternetAddress(recipientCc));
}
for (String recipientBcc : mailMessage.getBcc()) {
mimeMessage.addRecipient(javax.mail.Message.RecipientType.BCC, new InternetAddress(recipientBcc));
}
mimeMessage.setSubject(mailMessage.getSubject(), "utf-8");
String contentType = mailMessage.getContentType();
if (StringUtils.isEmpty(contentType)) {
contentType = "text/plain; charset=UTF-8";
}
mimeMessage.setContent(mailMessage.getBody(), contentType);
javax.mail.Transport t = session.getTransport("smtp");
if (StringUtils.isNotEmpty(mailServerConfigurationType.getUsername())) {
ProtectedStringType passwordProtected = mailServerConfigurationType.getPassword();
String password = null;
if (passwordProtected != null) {
try {
password = protector.decryptString(passwordProtected);
} catch (EncryptionException e) {
String msg = "Couldn't send mail message to " + mailMessage.getTo() + " via " + host + ", because the plaintext password value couldn't be obtained. Trying another mail server, if there is any.";
LoggingUtils.logException(LOGGER, msg, e);
resultForServer.recordFatalError(msg, e);
continue;
}
}
t.connect(mailServerConfigurationType.getUsername(), password);
} else {
t.connect();
}
t.sendMessage(mimeMessage, mimeMessage.getAllRecipients());
LOGGER.info("Message sent successfully to " + mailMessage.getTo() + " via server " + host + ".");
resultForServer.recordSuccess();
result.recordSuccess();
long duration = System.currentTimeMillis() - start;
task.recordState("Notification mail sent successfully via " + host + ", in " + duration + " ms overall.");
task.recordNotificationOperation(NAME, true, duration);
return;
} catch (MessagingException e) {
String msg = "Couldn't send mail message to " + mailMessage.getTo() + " via " + host + ", trying another mail server, if there is any";
LoggingUtils.logException(LOGGER, msg, e);
resultForServer.recordFatalError(msg, e);
task.recordState("Error sending notification mail via " + host);
}
}
LOGGER.warn("No more mail servers to try, mail notification to " + mailMessage.getTo() + " will not be sent.") ;
result.recordWarning("Mail notification to " + mailMessage.getTo() + " could not be sent.");
task.recordNotificationOperation(NAME, false, System.currentTimeMillis() - start);
}
private String formatToFile(Message mailMessage) {
return "============================================ " + "\n" +new Date() + "\n" + mailMessage.toString() + "\n\n";
}
@Override
public String getDefaultRecipientAddress(UserType recipient) {
return recipient.getEmailAddress();
}
@Override
public String getName() {
return NAME;
}
}