Unify SMTP mail sending (#4954)

* Add mail dependencies

* Create util to send SMTP mail

* Add unit tests to SMTP mail sender

* Use SMTP mail util on quota alert

* Use SMTP mail util on alert

* Use SMTP mail util on project

* Use SMTP mail util on usage alert

* Remove copyright line in license header

Co-authored-by: Gabriel Beims Bräscher <gabrascher@gmail.com>

* Remove copyright line in license header

Co-authored-by: Gabriel Beims Bräscher <gabrascher@gmail.com>

* Remove copyright line in license header

Co-authored-by: Gabriel Beims Bräscher <gabrascher@gmail.com>

* Remove copyright line in license header

Co-authored-by: Gabriel Beims Bräscher <gabrascher@gmail.com>

* Remove copyright line in license header

Co-authored-by: Gabriel Beims Bräscher <gabrascher@gmail.com>

Co-authored-by: Daniel Augusto Veronezi Salvador <daniel@scclouds.com.br>
Co-authored-by: Gabriel Beims Bräscher <gabrascher@gmail.com>
This commit is contained in:
Daniel Augusto Veronezi Salvador 2021-06-15 18:18:26 -03:00 committed by GitHub
parent bf6266188c
commit e962f0f271
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 1338 additions and 606 deletions

View File

@ -16,24 +16,15 @@
//under the License.
package org.apache.cloudstack.quota;
import java.io.UnsupportedEncodingException;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.concurrent.TimeUnit;
import javax.inject.Inject;
import javax.mail.Authenticator;
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.PasswordAuthentication;
import javax.mail.Session;
import javax.mail.URLName;
import javax.mail.internet.InternetAddress;
import javax.naming.ConfigurationException;
import org.apache.cloudstack.framework.config.dao.ConfigurationDao;
@ -55,15 +46,14 @@ import com.cloud.user.AccountVO;
import com.cloud.user.UserVO;
import com.cloud.user.dao.AccountDao;
import com.cloud.user.dao.UserDao;
import com.cloud.utils.NumbersUtil;
import com.cloud.utils.component.ManagerBase;
import com.cloud.utils.db.TransactionLegacy;
import com.google.common.base.Strings;
import com.sun.mail.smtp.SMTPMessage;
import com.sun.mail.smtp.SMTPSSLTransport;
import com.sun.mail.smtp.SMTPTransport;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang.BooleanUtils;
import java.util.HashSet;
import java.util.Set;
import org.apache.cloudstack.utils.mailing.MailAddress;
import org.apache.cloudstack.utils.mailing.SMTPMailProperties;
import org.apache.cloudstack.utils.mailing.SMTPMailSender;
import org.apache.commons.lang3.BooleanUtils;
@Component
public class QuotaAlertManagerImpl extends ManagerBase implements QuotaAlertManager {
@ -84,8 +74,9 @@ public class QuotaAlertManagerImpl extends ManagerBase implements QuotaAlertMana
@Inject
private QuotaManager _quotaManager;
private EmailQuotaAlert _emailQuotaAlert;
private boolean _lockAccountEnforcement = false;
private String senderAddress;
protected SMTPMailSender mailSender;
boolean _smtpDebug = false;
@ -109,19 +100,16 @@ public class QuotaAlertManagerImpl extends ManagerBase implements QuotaAlertMana
mergeConfigs(configs, params);
}
final String smtpHost = configs.get(QuotaConfig.QuotaSmtpHost.key());
int smtpPort = NumbersUtil.parseInt(configs.get(QuotaConfig.QuotaSmtpPort.key()), 25);
String useAuthStr = configs.get(QuotaConfig.QuotaSmtpAuthType.key());
boolean useAuth = ((useAuthStr != null) && Boolean.parseBoolean(useAuthStr));
senderAddress = configs.get(QuotaConfig.QuotaSmtpSender.key());
_lockAccountEnforcement = BooleanUtils.toBoolean(configs.get(QuotaConfig.QuotaEnableEnforcement.key()));
String smtpUsername = configs.get(QuotaConfig.QuotaSmtpUser.key());
String smtpPassword = configs.get(QuotaConfig.QuotaSmtpPassword.key());
String emailSender = configs.get(QuotaConfig.QuotaSmtpSender.key());
String smtpEnabledSecurityProtocols = configs.get(QuotaConfig.QuotaSmtpEnabledSecurityProtocols.key());
String useStartTLSStr = configs.get(QuotaConfig.QuotaSmtpUseStartTLS.key());
boolean useStartTLS = BooleanUtils.toBoolean(useStartTLSStr);
_lockAccountEnforcement = "true".equalsIgnoreCase(configs.get(QuotaConfig.QuotaEnableEnforcement.key()));
_emailQuotaAlert = new EmailQuotaAlert(smtpHost, smtpPort, useAuth, smtpUsername, smtpPassword, emailSender, smtpEnabledSecurityProtocols, useStartTLS, _smtpDebug);
String namespace = "quota.usage.smtp";
configs.put(String.format("%s.debug", namespace), String.valueOf(_smtpDebug));
configs.put(String.format("%s.username", namespace), smtpUsername);
mailSender = new SMTPMailSender(configs, namespace);
return true;
}
@ -234,7 +222,7 @@ public class QuotaAlertManagerImpl extends ManagerBase implements QuotaAlertMana
final String subject = templateEngine.replace(emailTemplate.getTemplateSubject());
final String body = templateEngine.replace(emailTemplate.getTemplateBody());
try {
_emailQuotaAlert.sendQuotaAlert(emailRecipients, subject, body);
sendQuotaAlert(emailRecipients, subject, body);
emailToBeSent.sentSuccessfully(_quotaAcc);
} catch (Exception e) {
s_logger.error(String.format("Unable to send quota alert email (subject=%s; body=%s) to account %s (%s) recipients (%s) due to error (%s)", subject, body, account.getAccountName(),
@ -337,99 +325,22 @@ public class QuotaAlertManagerImpl extends ManagerBase implements QuotaAlertMana
}
};
static class EmailQuotaAlert {
private final Session _smtpSession;
private final String _smtpHost;
private final int _smtpPort;
private final boolean _smtpUseAuth;
private final String _smtpUsername;
private final String _smtpPassword;
private final String _emailSender;
private final boolean smtpUseStartTLS;
protected void sendQuotaAlert(List<String> emails, String subject, String body) {
SMTPMailProperties mailProperties = new SMTPMailProperties();
public EmailQuotaAlert(String smtpHost, int smtpPort, boolean smtpUseAuth, final String smtpUsername, final String smtpPassword, String emailSender, String smtpEnabledSecurityProtocols, boolean smtpUseStartTLS, boolean smtpDebug) {
_smtpHost = smtpHost;
_smtpPort = smtpPort;
_smtpUseAuth = smtpUseAuth;
_smtpUsername = smtpUsername;
_smtpPassword = smtpPassword;
_emailSender = emailSender;
this.smtpUseStartTLS = smtpUseStartTLS;
mailProperties.setSender(new MailAddress(senderAddress));
mailProperties.setSubject(subject);
mailProperties.setContent(body);
mailProperties.setContentType("text/html; charset=utf-8");
if (!Strings.isNullOrEmpty(_smtpHost)) {
Properties smtpProps = new Properties();
smtpProps.put("mail.smtp.host", smtpHost);
smtpProps.put("mail.smtp.port", smtpPort);
smtpProps.put("mail.smtp.auth", "" + smtpUseAuth);
if (smtpUsername != null) {
smtpProps.put("mail.smtp.user", smtpUsername);
}
smtpProps.put("mail.smtps.host", smtpHost);
smtpProps.put("mail.smtps.port", smtpPort);
smtpProps.put("mail.smtps.auth", "" + smtpUseAuth);
if (!Strings.isNullOrEmpty(smtpUsername)) {
smtpProps.put("mail.smtps.user", smtpUsername);
}
if (StringUtils.isNotBlank(smtpEnabledSecurityProtocols)) {
smtpProps.put("mail.smtp.ssl.protocols", smtpEnabledSecurityProtocols);
}
if (smtpUseAuth) {
smtpProps.put("mail.smtp.starttls.enable", smtpUseStartTLS);
}
if (!Strings.isNullOrEmpty(smtpUsername) && !Strings.isNullOrEmpty(smtpPassword)) {
_smtpSession = Session.getInstance(smtpProps, new Authenticator() {
@Override
protected PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication(smtpUsername, smtpPassword);
}
});
} else {
_smtpSession = Session.getInstance(smtpProps);
}
_smtpSession.setDebug(smtpDebug);
} else {
_smtpSession = null;
}
Set<MailAddress> addresses = new HashSet<>();
for (String email : emails) {
addresses.add(new MailAddress(email));
}
public void sendQuotaAlert(List<String> emails, String subject, String body) throws MessagingException, UnsupportedEncodingException {
if (_smtpSession == null) {
s_logger.error("Unable to create smtp session.");
return;
}
SMTPMessage msg = new SMTPMessage(_smtpSession);
msg.setSender(new InternetAddress(_emailSender, _emailSender));
msg.setFrom(new InternetAddress(_emailSender, _emailSender));
mailProperties.setRecipients(addresses);
for (String email : emails) {
if (email != null && !email.isEmpty()) {
try {
InternetAddress address = new InternetAddress(email, email);
msg.addRecipient(Message.RecipientType.TO, address);
} catch (Exception pokemon) {
s_logger.error("Exception in creating address for:" + email, pokemon);
}
}
}
msg.setSubject(subject);
msg.setSentDate(new Date());
msg.setContent(body, "text/html; charset=utf-8");
msg.saveChanges();
SMTPTransport smtpTrans = null;
if (_smtpUseAuth && !this.smtpUseStartTLS) {
smtpTrans = new SMTPSSLTransport(_smtpSession, new URLName("smtp", _smtpHost, _smtpPort, null, _smtpUsername, _smtpPassword));
} else {
smtpTrans = new SMTPTransport(_smtpSession, new URLName("smtp", _smtpHost, _smtpPort, null, _smtpUsername, _smtpPassword));
}
smtpTrans.connect();
smtpTrans.sendMessage(msg, msg.getAllRecipients());
smtpTrans.close();
}
mailSender.sendMail(mailProperties);
}
}

View File

@ -52,6 +52,8 @@ import com.cloud.user.dao.UserDao;
import com.cloud.utils.db.TransactionLegacy;
import junit.framework.TestCase;
import org.apache.cloudstack.utils.mailing.SMTPMailProperties;
import org.apache.cloudstack.utils.mailing.SMTPMailSender;
@RunWith(MockitoJUnitRunner.class)
public class QuotaAlertManagerImplTest extends TestCase {
@ -68,8 +70,6 @@ public class QuotaAlertManagerImplTest extends TestCase {
private QuotaEmailTemplatesDao quotaEmailTemplateDao;
@Mock
private ConfigurationDao configDao;
@Mock
private QuotaAlertManagerImpl.EmailQuotaAlert emailQuotaAlert;
@Spy
@InjectMocks
@ -77,7 +77,6 @@ public class QuotaAlertManagerImplTest extends TestCase {
@Before
public void setup() throws IllegalAccessException, NoSuchFieldException, ConfigurationException {
// Dummy transaction stack setup
TransactionLegacy.open("QuotaAlertManagerImplTest");
}
@ -135,7 +134,8 @@ public class QuotaAlertManagerImplTest extends TestCase {
quotaAccount.setQuotaAlertDate(null);
quotaAccount.setQuotaEnforce(0);
QuotaAlertManagerImpl.DeferredQuotaEmail email = new QuotaAlertManagerImpl.DeferredQuotaEmail(account, quotaAccount, new BigDecimal(100), QuotaConfig.QuotaEmailTemplateTypes.QUOTA_LOW);
QuotaAlertManagerImpl.DeferredQuotaEmail email = new QuotaAlertManagerImpl.DeferredQuotaEmail(account, quotaAccount, new BigDecimal(100),
QuotaConfig.QuotaEmailTemplateTypes.QUOTA_LOW);
QuotaEmailTemplatesVO quotaEmailTemplatesVO = new QuotaEmailTemplatesVO();
quotaEmailTemplatesVO.setTemplateSubject("Low quota");
@ -156,9 +156,13 @@ public class QuotaAlertManagerImplTest extends TestCase {
users.add(user);
Mockito.when(userDao.listByAccount(Mockito.anyLong())).thenReturn(users);
quotaAlertManager.mailSender = Mockito.mock(SMTPMailSender.class);
Mockito.when(quotaAlertManager.mailSender.sendMail(Mockito.anyObject())).thenReturn(Boolean.TRUE);
quotaAlertManager.sendQuotaAlert(email);
assertTrue(email.getSendDate() != null);
Mockito.verify(emailQuotaAlert, Mockito.times(1)).sendQuotaAlert(Mockito.anyListOf(String.class), Mockito.anyString(), Mockito.anyString());
Mockito.verify(quotaAlertManager, Mockito.times(1)).sendQuotaAlert(Mockito.anyListOf(String.class), Mockito.anyString(), Mockito.anyString());
Mockito.verify(quotaAlertManager.mailSender, Mockito.times(1)).sendMail(Mockito.any(SMTPMailProperties.class));
}
@Test

View File

@ -23,20 +23,12 @@ import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Timer;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import javax.inject.Inject;
import javax.mail.Authenticator;
import javax.mail.Message.RecipientType;
import javax.mail.MessagingException;
import javax.mail.PasswordAuthentication;
import javax.mail.SendFailedException;
import javax.mail.Session;
import javax.mail.URLName;
import javax.mail.internet.InternetAddress;
import javax.naming.ConfigurationException;
import org.apache.cloudstack.framework.config.ConfigDepot;
@ -78,13 +70,15 @@ import com.cloud.resource.ResourceManager;
import com.cloud.service.ServiceOfferingVO;
import com.cloud.service.dao.ServiceOfferingDao;
import com.cloud.storage.StorageManager;
import com.cloud.utils.NumbersUtil;
import com.cloud.utils.component.ManagerBase;
import com.cloud.utils.concurrency.NamedThreadFactory;
import com.cloud.utils.db.SearchCriteria;
import com.sun.mail.smtp.SMTPMessage;
import com.sun.mail.smtp.SMTPSSLTransport;
import com.sun.mail.smtp.SMTPTransport;
import java.util.HashSet;
import java.util.Set;
import org.apache.cloudstack.utils.mailing.MailAddress;
import org.apache.cloudstack.utils.mailing.SMTPMailProperties;
import org.apache.cloudstack.utils.mailing.SMTPMailSender;
import org.apache.commons.lang3.math.NumberUtils;
public class AlertManagerImpl extends ManagerBase implements AlertManager, Configurable {
private static final Logger s_logger = Logger.getLogger(AlertManagerImpl.class.getName());
@ -94,7 +88,6 @@ public class AlertManagerImpl extends ManagerBase implements AlertManager, Confi
private static final DecimalFormat DfPct = new DecimalFormat("###.##");
private static final DecimalFormat DfWhole = new DecimalFormat("########");
private EmailAlert _emailAlert;
@Inject
private AlertDao _alertDao;
@Inject
@ -138,6 +131,10 @@ public class AlertManagerImpl extends ManagerBase implements AlertManager, Confi
private final ExecutorService _executor;
protected SMTPMailSender mailSender;
protected String[] recipients = null;
protected String senderAddress = null;
public AlertManagerImpl() {
_executor = Executors.newCachedThreadPool(new NamedThreadFactory("Email-Alerts-Sender"));
}
@ -148,27 +145,23 @@ public class AlertManagerImpl extends ManagerBase implements AlertManager, Confi
// set up the email system for alerts
String emailAddressList = configs.get("alert.email.addresses");
String[] emailAddresses = null;
if (emailAddressList != null) {
emailAddresses = emailAddressList.split(",");
recipients = emailAddressList.split(",");
}
String smtpHost = configs.get("alert.smtp.host");
int smtpPort = NumbersUtil.parseInt(configs.get("alert.smtp.port"), 25);
String useAuthStr = configs.get("alert.smtp.useAuth");
boolean useAuth = ((useAuthStr == null) ? false : Boolean.parseBoolean(useAuthStr));
String smtpUsername = configs.get("alert.smtp.username");
String smtpPassword = configs.get("alert.smtp.password");
String emailSender = configs.get("alert.email.sender");
String smtpDebugStr = configs.get("alert.smtp.debug");
int smtpTimeout = NumbersUtil.parseInt(configs.get("alert.smtp.timeout"), 30000);
int smtpConnectionTimeout = NumbersUtil.parseInt(configs.get("alert.smtp.connectiontimeout"), 30000);
boolean smtpDebug = false;
if (smtpDebugStr != null) {
smtpDebug = Boolean.parseBoolean(smtpDebugStr);
}
senderAddress = configs.get("alert.email.sender");
_emailAlert = new EmailAlert(emailAddresses, smtpHost, smtpPort, smtpConnectionTimeout, smtpTimeout, useAuth, smtpUsername, smtpPassword, emailSender, smtpDebug);
String namespace = "alert.smtp";
String timeoutConfig = String.format("%s.timeout", namespace);
String connectionTimeoutConfig = String.format("%s.connectiontimeout", namespace);
int smtpTimeout = NumberUtils.toInt(configs.get(timeoutConfig), 30000);
int smtpConnectionTimeout = NumberUtils.toInt(configs.get(connectionTimeoutConfig), 30000);
configs.put(timeoutConfig, String.valueOf(smtpTimeout));
configs.put(connectionTimeoutConfig, String.valueOf(smtpConnectionTimeout));
mailSender = new SMTPMailSender(configs, namespace);
String publicIPCapacityThreshold = _configDao.getValue(Config.PublicIpCapacityThreshold.key());
String privateIPCapacityThreshold = _configDao.getValue(Config.PrivateIpCapacityThreshold.key());
@ -231,9 +224,7 @@ public class AlertManagerImpl extends ManagerBase implements AlertManager, Confi
@Override
public void clearAlert(AlertType alertType, long dataCenterId, long podId) {
try {
if (_emailAlert != null) {
_emailAlert.clearAlert(alertType.getType(), dataCenterId, podId);
}
clearAlert(alertType.getType(), dataCenterId, podId);
} catch (Exception ex) {
s_logger.error("Problem clearing email alert", ex);
}
@ -248,8 +239,8 @@ public class AlertManagerImpl extends ManagerBase implements AlertManager, Confi
// TODO: queue up these messages and send them as one set of issues once a certain number of issues is reached? If that's the case,
// shouldn't we have a type/severity as part of the API so that severe errors get sent right away?
try {
if (_emailAlert != null) {
_emailAlert.sendAlert(alertType, dataCenterId, podId, null, subject, body);
if (mailSender != null) {
sendAlert(alertType, dataCenterId, podId, null, subject, body);
} else {
s_logger.warn("AlertType:: " + alertType + " | dataCenterId:: " + dataCenterId + " | podId:: " + podId +
" | message:: " + subject + " | body:: " + body);
@ -441,8 +432,7 @@ public class AlertManagerImpl extends ManagerBase implements AlertManager, Confi
recalculateCapacity();
// abort if we can't possibly send an alert...
if (_emailAlert == null) {
if (mailSender == null) {
return;
}
@ -642,7 +632,7 @@ public class AlertManagerImpl extends ManagerBase implements AlertManager, Confi
s_logger.debug(msgSubject);
s_logger.debug(msgContent);
}
_emailAlert.sendAlert(alertType, dc.getId(), podId, clusterId, msgSubject, msgContent);
sendAlert(alertType, dc.getId(), podId, clusterId, msgSubject, msgContent);
} catch (Exception ex) {
s_logger.error("Exception in CapacityChecker", ex);
}
@ -679,170 +669,73 @@ public class AlertManagerImpl extends ManagerBase implements AlertManager, Confi
}
class EmailAlert {
private Session _smtpSession;
private InternetAddress[] _recipientList;
private final String _smtpHost;
private int _smtpPort = -1;
private boolean _smtpUseAuth = false;
private final String _smtpUsername;
private final String _smtpPassword;
private final String _emailSender;
private int _smtpTimeout;
private int _smtpConnectionTimeout;
public EmailAlert(String[] recipientList, String smtpHost, int smtpPort, int smtpConnectionTimeout, int smtpTimeout, boolean smtpUseAuth,
final String smtpUsername,
final String smtpPassword, String emailSender, boolean smtpDebug) {
if (recipientList != null) {
_recipientList = new InternetAddress[recipientList.length];
for (int i = 0; i < recipientList.length; i++) {
try {
_recipientList[i] = new InternetAddress(recipientList[i], recipientList[i]);
} catch (Exception ex) {
s_logger.error("Exception creating address for: " + recipientList[i], ex);
}
}
}
_smtpHost = smtpHost;
_smtpPort = smtpPort;
_smtpUseAuth = smtpUseAuth;
_smtpUsername = smtpUsername;
_smtpPassword = smtpPassword;
_emailSender = emailSender;
_smtpTimeout = smtpTimeout;
_smtpConnectionTimeout = smtpConnectionTimeout;
if (_smtpHost != null) {
Properties smtpProps = new Properties();
smtpProps.put("mail.smtp.host", smtpHost);
smtpProps.put("mail.smtp.port", smtpPort);
smtpProps.put("mail.smtp.auth", "" + smtpUseAuth);
smtpProps.put("mail.smtp.timeout", _smtpTimeout);
smtpProps.put("mail.smtp.connectiontimeout", _smtpConnectionTimeout);
if (smtpUsername != null) {
smtpProps.put("mail.smtp.user", smtpUsername);
}
smtpProps.put("mail.smtps.host", smtpHost);
smtpProps.put("mail.smtps.port", smtpPort);
smtpProps.put("mail.smtps.auth", "" + smtpUseAuth);
smtpProps.put("mail.smtps.timeout", _smtpTimeout);
smtpProps.put("mail.smtps.connectiontimeout", _smtpConnectionTimeout);
if (smtpUsername != null) {
smtpProps.put("mail.smtps.user", smtpUsername);
}
if ((smtpUsername != null) && (smtpPassword != null)) {
_smtpSession = Session.getInstance(smtpProps, new Authenticator() {
@Override
protected PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication(smtpUsername, smtpPassword);
}
});
} else {
_smtpSession = Session.getInstance(smtpProps);
}
_smtpSession.setDebug(smtpDebug);
} else {
_smtpSession = null;
public void clearAlert(short alertType, long dataCenterId, Long podId) {
if (alertType != -1) {
AlertVO alert = _alertDao.getLastAlert(alertType, dataCenterId, podId, null);
if (alert != null) {
AlertVO updatedAlert = _alertDao.createForUpdate();
updatedAlert.setResolved(new Date());
_alertDao.update(alert.getId(), updatedAlert);
}
}
}
// TODO: make sure this handles SSL transport (useAuth is true) and regular
public void sendAlert(AlertType alertType, long dataCenterId, Long podId, Long clusterId, String subject, String content) throws MessagingException,
UnsupportedEncodingException {
s_logger.warn("AlertType:: " + alertType + " | dataCenterId:: " + dataCenterId + " | podId:: " +
podId + " | clusterId:: " + clusterId + " | message:: " + subject);
AlertVO alert = null;
if ((alertType != AlertManager.AlertType.ALERT_TYPE_HOST) &&
(alertType != AlertManager.AlertType.ALERT_TYPE_USERVM) &&
(alertType != AlertManager.AlertType.ALERT_TYPE_DOMAIN_ROUTER) &&
(alertType != AlertManager.AlertType.ALERT_TYPE_CONSOLE_PROXY) &&
(alertType != AlertManager.AlertType.ALERT_TYPE_SSVM) &&
(alertType != AlertManager.AlertType.ALERT_TYPE_STORAGE_MISC) &&
(alertType != AlertManager.AlertType.ALERT_TYPE_MANAGMENT_NODE) &&
(alertType != AlertManager.AlertType.ALERT_TYPE_RESOURCE_LIMIT_EXCEEDED) &&
(alertType != AlertManager.AlertType.ALERT_TYPE_UPLOAD_FAILED) &&
(alertType != AlertManager.AlertType.ALERT_TYPE_OOBM_AUTH_ERROR) &&
(alertType != AlertManager.AlertType.ALERT_TYPE_HA_ACTION) &&
(alertType != AlertManager.AlertType.ALERT_TYPE_CA_CERT) &&
(alertType != AlertManager.AlertType.ALERT_TYPE_VM_SNAPSHOT)) {
alert = _alertDao.getLastAlert(alertType.getType(), dataCenterId, podId, clusterId);
}
public void sendAlert(AlertType alertType, long dataCenterId, Long podId, Long clusterId, String subject, String content)
throws MessagingException, UnsupportedEncodingException {
s_logger.warn(String.format("alertType=[%s] dataCenterId=[%s] podId=[%s] clusterId=[%s] message=[%s].", alertType, dataCenterId, podId, clusterId, subject));
AlertVO alert = null;
if ((alertType != AlertManager.AlertType.ALERT_TYPE_HOST) && (alertType != AlertManager.AlertType.ALERT_TYPE_USERVM)
&& (alertType != AlertManager.AlertType.ALERT_TYPE_DOMAIN_ROUTER) && (alertType != AlertManager.AlertType.ALERT_TYPE_CONSOLE_PROXY)
&& (alertType != AlertManager.AlertType.ALERT_TYPE_SSVM) && (alertType != AlertManager.AlertType.ALERT_TYPE_STORAGE_MISC)
&& (alertType != AlertManager.AlertType.ALERT_TYPE_MANAGMENT_NODE) && (alertType != AlertManager.AlertType.ALERT_TYPE_RESOURCE_LIMIT_EXCEEDED)
&& (alertType != AlertManager.AlertType.ALERT_TYPE_UPLOAD_FAILED) && (alertType != AlertManager.AlertType.ALERT_TYPE_OOBM_AUTH_ERROR)
&& (alertType != AlertManager.AlertType.ALERT_TYPE_HA_ACTION) && (alertType != AlertManager.AlertType.ALERT_TYPE_CA_CERT)) {
alert = _alertDao.getLastAlert(alertType.getType(), dataCenterId, podId, clusterId);
}
if (alert == null) {
// set up a new alert
AlertVO newAlert = new AlertVO();
newAlert.setType(alertType.getType());
newAlert.setSubject(subject);
newAlert.setContent(content);
newAlert.setClusterId(clusterId);
newAlert.setPodId(podId);
newAlert.setDataCenterId(dataCenterId);
newAlert.setSentCount(1); // Initialize sent count to 1 since we are now sending an alert.
newAlert.setLastSent(new Date());
newAlert.setName(alertType.getName());
_alertDao.persist(newAlert);
} else {
if (s_logger.isDebugEnabled()) {
if (alert == null) {
AlertVO newAlert = new AlertVO();
newAlert.setType(alertType.getType());
newAlert.setSubject(subject);
newAlert.setContent(content);
newAlert.setClusterId(clusterId);
newAlert.setPodId(podId);
newAlert.setDataCenterId(dataCenterId);
newAlert.setSentCount(1);
newAlert.setLastSent(new Date());
newAlert.setName(alertType.getName());
_alertDao.persist(newAlert);
} else {
if (s_logger.isDebugEnabled()) {
s_logger.debug("Have already sent: " + alert.getSentCount() + " emails for alert type '" + alertType + "' -- skipping send email");
}
return;
}
if (_smtpSession != null) {
SMTPMessage msg = new SMTPMessage(_smtpSession);
msg.setSender(new InternetAddress(_emailSender, _emailSender));
msg.setFrom(new InternetAddress(_emailSender, _emailSender));
for (InternetAddress address : _recipientList) {
msg.addRecipient(RecipientType.TO, address);
}
msg.setSubject(subject);
msg.setSentDate(new Date());
msg.setContent(content, "text/plain");
msg.saveChanges();
SMTPTransport smtpTrans = null;
if (_smtpUseAuth) {
smtpTrans = new SMTPSSLTransport(_smtpSession, new URLName("smtp", _smtpHost, _smtpPort, null, _smtpUsername, _smtpPassword));
} else {
smtpTrans = new SMTPTransport(_smtpSession, new URLName("smtp", _smtpHost, _smtpPort, null, _smtpUsername, _smtpPassword));
}
sendMessage(smtpTrans, msg);
}
return;
}
private void sendMessage(final SMTPTransport smtpTrans, final SMTPMessage msg) {
_executor.execute(new Runnable() {
@Override
public void run() {
try {
smtpTrans.connect();
smtpTrans.sendMessage(msg, msg.getAllRecipients());
smtpTrans.close();
} catch (SendFailedException e) {
s_logger.error(" Failed to send email alert " + e);
} catch (MessagingException e) {
s_logger.error(" Failed to send email alert " + e);
}
}
});
SMTPMailProperties mailProps = new SMTPMailProperties();
mailProps.setSender(new MailAddress(senderAddress));
mailProps.setSubject(subject);
mailProps.setContent(content);
mailProps.setContentType("text/plain");
Set<MailAddress> addresses = new HashSet<>();
for (String recipient : recipients) {
addresses.add(new MailAddress(recipient));
}
public void clearAlert(short alertType, long dataCenterId, Long podId) {
if (alertType != -1) {
AlertVO alert = _alertDao.getLastAlert(alertType, dataCenterId, podId, null);
if (alert != null) {
AlertVO updatedAlert = _alertDao.createForUpdate();
updatedAlert.setResolved(new Date());
_alertDao.update(alert.getId(), updatedAlert);
}
mailProps.setRecipients(addresses);
sendMessage(mailProps);
}
private void sendMessage(SMTPMailProperties mailProps) {
_executor.execute(new Runnable() {
@Override
public void run() {
mailSender.sendMail(mailProps);
}
}
});
}
private static String formatPercent(double percentage) {

View File

@ -17,11 +17,9 @@
package com.cloud.projects;
import java.io.UnsupportedEncodingException;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Properties;
import java.util.Random;
import java.util.TimeZone;
import java.util.UUID;
@ -31,13 +29,7 @@ import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import javax.inject.Inject;
import javax.mail.Authenticator;
import javax.mail.Message.RecipientType;
import javax.mail.MessagingException;
import javax.mail.PasswordAuthentication;
import javax.mail.Session;
import javax.mail.URLName;
import javax.mail.internet.InternetAddress;
import javax.naming.ConfigurationException;
import org.apache.cloudstack.acl.ProjectRole;
@ -79,8 +71,6 @@ import com.cloud.user.ResourceLimitService;
import com.cloud.user.User;
import com.cloud.user.dao.AccountDao;
import com.cloud.user.dao.UserDao;
import com.cloud.utils.DateUtil;
import com.cloud.utils.NumbersUtil;
import com.cloud.utils.component.ManagerBase;
import com.cloud.utils.concurrency.NamedThreadFactory;
import com.cloud.utils.db.DB;
@ -90,14 +80,16 @@ import com.cloud.utils.db.TransactionCallbackNoReturn;
import com.cloud.utils.db.TransactionCallbackWithExceptionNoReturn;
import com.cloud.utils.db.TransactionStatus;
import com.cloud.utils.exception.CloudRuntimeException;
import com.sun.mail.smtp.SMTPMessage;
import com.sun.mail.smtp.SMTPSSLTransport;
import com.sun.mail.smtp.SMTPTransport;
import java.util.HashSet;
import java.util.Set;
import org.apache.cloudstack.utils.mailing.MailAddress;
import org.apache.cloudstack.utils.mailing.SMTPMailProperties;
import org.apache.cloudstack.utils.mailing.SMTPMailSender;
import org.apache.commons.lang3.BooleanUtils;
@Component
public class ProjectManagerImpl extends ManagerBase implements ProjectManager {
public static final Logger s_logger = Logger.getLogger(ProjectManagerImpl.class);
private EmailInvite _emailInvite;
@Inject
private DomainDao _domainDao;
@ -137,33 +129,23 @@ public class ProjectManagerImpl extends ManagerBase implements ProjectManager {
protected boolean _allowUserToCreateProject = true;
protected ScheduledExecutorService _executor;
protected int _projectCleanupExpInvInterval = 60; //Interval defining how often project invitation cleanup thread is running
private String senderAddress;
protected SMTPMailSender mailSender;
@Override
public boolean configure(final String name, final Map<String, Object> params) throws ConfigurationException {
Map<String, String> configs = _configDao.getConfiguration(params);
_invitationRequired = Boolean.valueOf(configs.get(Config.ProjectInviteRequired.key()));
_invitationRequired = BooleanUtils.toBoolean(configs.get(Config.ProjectInviteRequired.key()));
String value = configs.get(Config.ProjectInvitationExpirationTime.key());
_invitationTimeOut = Long.parseLong(value != null ? value : "86400") * 1000;
_allowUserToCreateProject = Boolean.valueOf(configs.get(Config.AllowUserToCreateProject.key()));
_allowUserToCreateProject = BooleanUtils.toBoolean(configs.get(Config.AllowUserToCreateProject.key()));
senderAddress = configs.get("project.email.sender");
// set up the email system for project invitations
String namespace = "project.smtp";
String smtpHost = configs.get("project.smtp.host");
int smtpPort = NumbersUtil.parseInt(configs.get("project.smtp.port"), 25);
String useAuthStr = configs.get("project.smtp.useAuth");
boolean useAuth = ((useAuthStr == null) ? false : Boolean.parseBoolean(useAuthStr));
String smtpUsername = configs.get("project.smtp.username");
String smtpPassword = configs.get("project.smtp.password");
String emailSender = configs.get("project.email.sender");
String smtpDebugStr = configs.get("project.smtp.debug");
boolean smtpDebug = false;
if (smtpDebugStr != null) {
smtpDebug = Boolean.parseBoolean(smtpDebugStr);
}
_emailInvite = new EmailInvite(smtpHost, smtpPort, useAuth, smtpUsername, smtpPassword, emailSender, smtpDebug);
mailSender = new SMTPMailSender(configs, namespace);
_executor = Executors.newScheduledThreadPool(1, new NamedThreadFactory("Project-ExpireInvitations"));
return true;
@ -1081,7 +1063,7 @@ public class ProjectManagerImpl extends ManagerBase implements ProjectManager {
ProjectInvitation projectInvitation = _projectInvitationDao.persist(projectInvitationVO);
try {
_emailInvite.sendInvite(token, email, project.getId());
sendInvite(token, email, project.getId());
} catch (Exception ex) {
s_logger.warn("Failed to send project id=" + project + " invitation to the email " + email + "; removing the invitation record from the db", ex);
_projectInvitationDao.remove(projectInvitation.getId());
@ -1091,6 +1073,27 @@ public class ProjectManagerImpl extends ManagerBase implements ProjectManager {
return projectInvitation;
}
protected void sendInvite(String token, String email, long projectId) throws MessagingException, UnsupportedEncodingException {
String subject = String.format("You are invited to join the cloud stack project id=[%s].", projectId);
String content = String.format("You've been invited to join the CloudStack project id=[%s]. Please use token [%s] to complete registration", projectId, token);
SMTPMailProperties mailProperties = new SMTPMailProperties();
mailProperties.setSender(new MailAddress(senderAddress));
mailProperties.setSubject(subject);
mailProperties.setContent(content);
mailProperties.setContentType("text/plain");
Set<MailAddress> addresses = new HashSet<>();
addresses.add(new MailAddress(email));
mailProperties.setRecipients(addresses);
mailSender.sendMail(mailProperties);
}
private boolean expireInvitation(ProjectInvitationVO invite) {
s_logger.debug("Expiring invitation id=" + invite.getId());
invite.setState(ProjectInvitation.State.Expired);
@ -1305,91 +1308,6 @@ public class ProjectManagerImpl extends ManagerBase implements ProjectManager {
}
return sb.toString();
}
class EmailInvite {
private Session _smtpSession;
private final String _smtpHost;
private int _smtpPort = -1;
private boolean _smtpUseAuth = false;
private final String _smtpUsername;
private final String _smtpPassword;
private final String _emailSender;
public EmailInvite(String smtpHost, int smtpPort, boolean smtpUseAuth, final String smtpUsername, final String smtpPassword, String emailSender, boolean smtpDebug) {
_smtpHost = smtpHost;
_smtpPort = smtpPort;
_smtpUseAuth = smtpUseAuth;
_smtpUsername = smtpUsername;
_smtpPassword = smtpPassword;
_emailSender = emailSender;
if (_smtpHost != null) {
Properties smtpProps = new Properties();
smtpProps.put("mail.smtp.host", smtpHost);
smtpProps.put("mail.smtp.port", smtpPort);
smtpProps.put("mail.smtp.auth", "" + smtpUseAuth);
if (smtpUsername != null) {
smtpProps.put("mail.smtp.user", smtpUsername);
}
smtpProps.put("mail.smtps.host", smtpHost);
smtpProps.put("mail.smtps.port", smtpPort);
smtpProps.put("mail.smtps.auth", "" + smtpUseAuth);
if (smtpUsername != null) {
smtpProps.put("mail.smtps.user", smtpUsername);
}
if ((smtpUsername != null) && (smtpPassword != null)) {
_smtpSession = Session.getInstance(smtpProps, new Authenticator() {
@Override
protected PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication(smtpUsername, smtpPassword);
}
});
} else {
_smtpSession = Session.getInstance(smtpProps);
}
_smtpSession.setDebug(smtpDebug);
} else {
_smtpSession = null;
}
}
public void sendInvite(String token, String email, long projectId) throws MessagingException, UnsupportedEncodingException {
if (_smtpSession != null) {
InternetAddress address = null;
if (email != null) {
try {
address = new InternetAddress(email, email);
} catch (Exception ex) {
s_logger.error("Exception creating address for: " + email, ex);
}
}
String content = "You've been invited to join the CloudStack project id=" + projectId + ". Please use token " + token + " to complete registration";
SMTPMessage msg = new SMTPMessage(_smtpSession);
msg.setSender(new InternetAddress(_emailSender, _emailSender));
msg.setFrom(new InternetAddress(_emailSender, _emailSender));
msg.addRecipient(RecipientType.TO, address);
msg.setSubject("You are invited to join the cloud stack project id=" + projectId);
msg.setSentDate(new Date(DateUtil.currentGMTTime().getTime() >> 10));
msg.setContent(content, "text/plain");
msg.saveChanges();
SMTPTransport smtpTrans = null;
if (_smtpUseAuth) {
smtpTrans = new SMTPSSLTransport(_smtpSession, new URLName("smtp", _smtpHost, _smtpPort, null, _smtpUsername, _smtpPassword));
} else {
smtpTrans = new SMTPTransport(_smtpSession, new URLName("smtp", _smtpHost, _smtpPort, null, _smtpUsername, _smtpPassword));
}
smtpTrans.connect();
smtpTrans.sendMessage(msg, msg.getAllRecipients());
smtpTrans.close();
} else {
throw new CloudRuntimeException("Unable to send email invitation; smtp ses");
}
}
}
@Override
@DB

View File

@ -16,19 +16,10 @@
// under the License.
package com.cloud.usage;
import java.io.UnsupportedEncodingException;
import java.util.Date;
import java.util.Map;
import java.util.Properties;
import javax.inject.Inject;
import javax.mail.Authenticator;
import javax.mail.Message.RecipientType;
import javax.mail.MessagingException;
import javax.mail.PasswordAuthentication;
import javax.mail.Session;
import javax.mail.URLName;
import javax.mail.internet.InternetAddress;
import javax.naming.ConfigurationException;
import org.apache.cloudstack.framework.config.dao.ConfigurationDao;
@ -38,18 +29,21 @@ import org.springframework.stereotype.Component;
import com.cloud.alert.AlertManager;
import com.cloud.alert.AlertVO;
import com.cloud.alert.dao.AlertDao;
import com.cloud.utils.NumbersUtil;
import com.cloud.utils.component.ManagerBase;
import com.sun.mail.smtp.SMTPMessage;
import com.sun.mail.smtp.SMTPSSLTransport;
import com.sun.mail.smtp.SMTPTransport;
import java.util.HashSet;
import java.util.Set;
import org.apache.cloudstack.utils.mailing.MailAddress;
import org.apache.cloudstack.utils.mailing.SMTPMailProperties;
import org.apache.cloudstack.utils.mailing.SMTPMailSender;
@Component
public class UsageAlertManagerImpl extends ManagerBase implements AlertManager {
private static final Logger s_logger = Logger.getLogger(UsageAlertManagerImpl.class.getName());
private static final Logger s_alertsLogger = Logger.getLogger("org.apache.cloudstack.alerts");
private EmailAlert _emailAlert;
private String senderAddress;
protected SMTPMailSender mailSender;
protected String[] recipients;
@Inject
private AlertDao _alertDao;
@Inject
@ -59,185 +53,75 @@ public class UsageAlertManagerImpl extends ManagerBase implements AlertManager {
public boolean configure(String name, Map<String, Object> params) throws ConfigurationException {
Map<String, String> configs = _configDao.getConfiguration("management-server", params);
// set up the email system for alerts
senderAddress = configs.get("alert.email.sender");
String emailAddressList = configs.get("alert.email.addresses");
String[] emailAddresses = null;
recipients = null;
if (emailAddressList != null) {
emailAddresses = emailAddressList.split(",");
recipients = emailAddressList.split(",");
}
String smtpHost = configs.get("alert.smtp.host");
int smtpPort = NumbersUtil.parseInt(configs.get("alert.smtp.port"), 25);
String useAuthStr = configs.get("alert.smtp.useAuth");
boolean useAuth = ((useAuthStr == null) ? false : Boolean.parseBoolean(useAuthStr));
String smtpUsername = configs.get("alert.smtp.username");
String smtpPassword = configs.get("alert.smtp.password");
String emailSender = configs.get("alert.email.sender");
String smtpDebugStr = configs.get("alert.smtp.debug");
boolean smtpDebug = false;
if (smtpDebugStr != null) {
smtpDebug = Boolean.parseBoolean(smtpDebugStr);
}
String namespace = "alert.smtp";
mailSender = new SMTPMailSender(configs, namespace);
_emailAlert = new EmailAlert(emailAddresses, smtpHost, smtpPort, useAuth, smtpUsername, smtpPassword, emailSender, smtpDebug);
return true;
}
@Override
public void clearAlert(AlertType alertType, long dataCenterId, long podId) {
try {
if (_emailAlert != null) {
_emailAlert.clearAlert(alertType.getType(), dataCenterId, podId);
}
clearAlert(alertType.getType(), dataCenterId, podId);
} catch (Exception ex) {
s_logger.error("Problem clearing email alert", ex);
}
}
@Override
public void sendAlert(AlertType alertType, long dataCenterId, Long podId, String subject, String body) {
// TODO: queue up these messages and send them as one set of issues once a certain number of issues is reached? If that's the case,
// shouldn't we have a type/severity as part of the API so that severe errors get sent right away?
try {
if (_emailAlert != null) {
_emailAlert.sendAlert(alertType, dataCenterId, podId, subject, body);
} else {
s_alertsLogger.warn(" alertType:: " + alertType + " // dataCenterId:: " + dataCenterId + " // podId:: " + podId + " // clusterId:: " + null +
" // message:: " + subject + " // body:: " + body);
}
} catch (Exception ex) {
s_logger.error("Problem sending email alert", ex);
public void sendAlert(AlertType alertType, long dataCenterId, Long podId, String subject, String content) {
AlertVO alert = null;
if ((alertType != AlertManager.AlertType.ALERT_TYPE_HOST) && (alertType != AlertManager.AlertType.ALERT_TYPE_USERVM)
&& (alertType != AlertManager.AlertType.ALERT_TYPE_DOMAIN_ROUTER) && (alertType != AlertManager.AlertType.ALERT_TYPE_CONSOLE_PROXY)
&& (alertType != AlertManager.AlertType.ALERT_TYPE_SSVM) && (alertType != AlertManager.AlertType.ALERT_TYPE_STORAGE_MISC)
&& (alertType != AlertManager.AlertType.ALERT_TYPE_MANAGMENT_NODE)) {
alert = _alertDao.getLastAlert(alertType.getType(), dataCenterId, podId);
}
if (alert == null) {
AlertVO newAlert = new AlertVO();
newAlert.setType(alertType.getType());
newAlert.setSubject(subject);
newAlert.setPodId(podId);
newAlert.setDataCenterId(dataCenterId);
newAlert.setSentCount(1);
newAlert.setLastSent(new Date());
newAlert.setName(alertType.getName());
_alertDao.persist(newAlert);
} else {
s_logger.debug(String.format("Have already sent: [%s] emails for alert type [%s] -- skipping send email.", alert.getSentCount(), alertType));
return;
}
SMTPMailProperties mailProps = new SMTPMailProperties();
mailProps.setSender(new MailAddress(senderAddress));
mailProps.setSubject(subject);
mailProps.setContent(content);
mailProps.setContentType("text/plain");
Set<MailAddress> addresses = new HashSet<>();
for (String recipient : recipients) {
addresses.add(new MailAddress(recipient));
}
mailProps.setRecipients(addresses);
mailSender.sendMail(mailProps);
}
class EmailAlert {
private Session _smtpSession;
private InternetAddress[] _recipientList;
private final String _smtpHost;
private int _smtpPort = -1;
private boolean _smtpUseAuth = false;
private final String _smtpUsername;
private final String _smtpPassword;
private final String _emailSender;
public EmailAlert(String[] recipientList, String smtpHost, int smtpPort, boolean smtpUseAuth, final String smtpUsername, final String smtpPassword,
String emailSender, boolean smtpDebug) {
if (recipientList != null) {
_recipientList = new InternetAddress[recipientList.length];
for (int i = 0; i < recipientList.length; i++) {
try {
_recipientList[i] = new InternetAddress(recipientList[i], recipientList[i]);
} catch (Exception ex) {
s_logger.error("Exception creating address for: " + recipientList[i], ex);
}
}
}
_smtpHost = smtpHost;
_smtpPort = smtpPort;
_smtpUseAuth = smtpUseAuth;
_smtpUsername = smtpUsername;
_smtpPassword = smtpPassword;
_emailSender = emailSender;
if (_smtpHost != null) {
Properties smtpProps = new Properties();
smtpProps.put("mail.smtp.host", smtpHost);
smtpProps.put("mail.smtp.port", smtpPort);
smtpProps.put("mail.smtp.auth", "" + smtpUseAuth);
if (smtpUsername != null) {
smtpProps.put("mail.smtp.user", smtpUsername);
}
smtpProps.put("mail.smtps.host", smtpHost);
smtpProps.put("mail.smtps.port", smtpPort);
smtpProps.put("mail.smtps.auth", "" + smtpUseAuth);
if (smtpUsername != null) {
smtpProps.put("mail.smtps.user", smtpUsername);
}
if ((smtpUsername != null) && (smtpPassword != null)) {
_smtpSession = Session.getInstance(smtpProps, new Authenticator() {
@Override
protected PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication(smtpUsername, smtpPassword);
}
});
} else {
_smtpSession = Session.getInstance(smtpProps);
}
_smtpSession.setDebug(smtpDebug);
} else {
_smtpSession = null;
}
}
// TODO: make sure this handles SSL transport (useAuth is true) and regular
protected void sendAlert(AlertType alertType, long dataCenterId, Long podId, String subject, String content) throws MessagingException,
UnsupportedEncodingException {
s_alertsLogger.warn(" alertType:: " + alertType + " // dataCenterId:: " + dataCenterId + " // podId:: " +
podId + " // clusterId:: " + null + " // message:: " + subject);
AlertVO alert = null;
if ((alertType != AlertManager.AlertType.ALERT_TYPE_HOST) &&
(alertType != AlertManager.AlertType.ALERT_TYPE_USERVM) &&
(alertType != AlertManager.AlertType.ALERT_TYPE_DOMAIN_ROUTER) &&
(alertType != AlertManager.AlertType.ALERT_TYPE_CONSOLE_PROXY) &&
(alertType != AlertManager.AlertType.ALERT_TYPE_SSVM) &&
(alertType != AlertManager.AlertType.ALERT_TYPE_STORAGE_MISC) &&
(alertType != AlertManager.AlertType.ALERT_TYPE_MANAGMENT_NODE)) {
alert = _alertDao.getLastAlert(alertType.getType(), dataCenterId, podId);
}
if (alert == null) {
// set up a new alert
AlertVO newAlert = new AlertVO();
newAlert.setType(alertType.getType());
newAlert.setSubject(subject);
newAlert.setPodId(podId);
newAlert.setDataCenterId(dataCenterId);
newAlert.setSentCount(1); // initialize sent count to 1 since we are now sending an alert
newAlert.setLastSent(new Date());
newAlert.setName(alertType.getName());
_alertDao.persist(newAlert);
} else {
if (s_logger.isDebugEnabled()) {
s_logger.debug("Have already sent: " + alert.getSentCount() + " emails for alert type '" + alertType + "' -- skipping send email");
}
return;
}
if (_smtpSession != null) {
SMTPMessage msg = new SMTPMessage(_smtpSession);
msg.setSender(new InternetAddress(_emailSender, _emailSender));
msg.setFrom(new InternetAddress(_emailSender, _emailSender));
for (InternetAddress address : _recipientList) {
msg.addRecipient(RecipientType.TO, address);
}
msg.setSubject(subject);
msg.setSentDate(new Date());
msg.setContent(content, "text/plain");
msg.saveChanges();
SMTPTransport smtpTrans = null;
if (_smtpUseAuth) {
smtpTrans = new SMTPSSLTransport(_smtpSession, new URLName("smtp", _smtpHost, _smtpPort, null, _smtpUsername, _smtpPassword));
} else {
smtpTrans = new SMTPTransport(_smtpSession, new URLName("smtp", _smtpHost, _smtpPort, null, _smtpUsername, _smtpPassword));
}
smtpTrans.connect();
smtpTrans.sendMessage(msg, msg.getAllRecipients());
smtpTrans.close();
}
}
public void clearAlert(short alertType, long dataCenterId, Long podId) {
if (alertType != -1) {
AlertVO alert = _alertDao.getLastAlert(alertType, dataCenterId, podId);
if (alert != null) {
AlertVO updatedAlert = _alertDao.createForUpdate();
updatedAlert.setResolved(new Date());
_alertDao.update(alert.getId(), updatedAlert);
}
public void clearAlert(short alertType, long dataCenterId, Long podId) {
if (alertType != -1) {
AlertVO alert = _alertDao.getLastAlert(alertType, dataCenterId, podId);
if (alert != null) {
AlertVO updatedAlert = _alertDao.createForUpdate();
updatedAlert.setResolved(new Date());
_alertDao.update(alert.getId(), updatedAlert);
}
}
}
@ -254,7 +138,7 @@ public class UsageAlertManagerImpl extends ManagerBase implements AlertManager {
sendAlert(alertType, dataCenterId, podId, msg, msg);
return true;
} catch (Exception ex) {
s_logger.warn("Failed to generate an alert of type=" + alertType + "; msg=" + msg);
s_logger.warn("Failed to generate an alert of type=" + alertType + "; msg=" + msg, ex);
return false;
}
}

View File

@ -184,6 +184,15 @@
<artifactId>commons-compress</artifactId>
<version>${cs.commons-compress.version}</version>
</dependency>
<dependency>
<groupId>javax.mail</groupId>
<artifactId>mail</artifactId>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-email</artifactId>
<version>1.5</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>

View File

@ -0,0 +1,63 @@
/*
*
* 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 org.apache.cloudstack.utils.mailing;
import org.apache.commons.lang3.builder.EqualsBuilder;
import org.apache.commons.lang3.builder.HashCodeBuilder;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
public class MailAddress {
private final String address;
private final String personal;
public MailAddress(String address) {
this.address = address;
this.personal = address;
}
public MailAddress(String address, String personal) {
this.address = address;
this.personal = personal;
}
public String getAddress() {
return address;
}
public String getPersonal() {
return personal;
}
@Override
public int hashCode() {
return HashCodeBuilder.reflectionHashCode(this);
}
@Override
public boolean equals(Object obj) {
String[] excludedFields = {"personal"};
return EqualsBuilder.reflectionEquals(this, obj, excludedFields);
}
@Override
public String toString() {
ToStringBuilder tsb = new ToStringBuilder(this, ToStringStyle.JSON_STYLE);
tsb.append("mailAddress", address);
return tsb.build();
}
}

View File

@ -0,0 +1,89 @@
/*
*
* 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 org.apache.cloudstack.utils.mailing;
import java.util.Date;
import java.util.Set;
public class SMTPMailProperties {
private MailAddress sender;
private MailAddress from;
private Set<MailAddress> recipients;
private String subject;
private Date sentDate;
private Object content;
private String contentType;
public SMTPMailProperties() {
}
public MailAddress getSender() {
return sender;
}
public void setSender(MailAddress sender) {
this.sender = sender;
}
public MailAddress getFrom() {
return from;
}
public void setFrom(MailAddress from) {
this.from = from;
}
public Set<MailAddress> getRecipients() {
return recipients;
}
public void setRecipients(Set<MailAddress> recipients) {
this.recipients = recipients;
}
public String getSubject() {
return subject;
}
public void setSubject(String subject) {
this.subject = subject;
}
public Date getSentDate() {
return sentDate;
}
public void setSentDate(Date sentDate) {
this.sentDate = sentDate;
}
public Object getContent() {
return content;
}
public void setContent(Object content) {
this.content = content;
}
public String getContentType() {
return contentType;
}
public void setContentType(String contentType) {
this.contentType = contentType;
}
}

View File

@ -0,0 +1,231 @@
/*
*
* 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 org.apache.cloudstack.utils.mailing;
import com.sun.mail.smtp.SMTPMessage;
import com.sun.mail.smtp.SMTPSSLTransport;
import com.sun.mail.smtp.SMTPTransport;
import java.io.UnsupportedEncodingException;
import java.util.Date;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import javax.mail.Authenticator;
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.PasswordAuthentication;
import javax.mail.Session;
import javax.mail.URLName;
import javax.mail.internet.InternetAddress;
import org.apache.commons.lang3.BooleanUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.math.NumberUtils;
import org.apache.commons.mail.EmailConstants;
import org.apache.log4j.Logger;
public class SMTPMailSender {
private Logger logger = Logger.getLogger(SMTPMailSender.class);
protected Session session = null;
protected SMTPSessionProperties sessionProps;
protected static final String CONFIG_HOST = "host";
protected static final String CONFIG_PORT = "port";
protected static final String CONFIG_USE_AUTH = "useAuth";
protected static final String CONFIG_USERNAME = "username";
protected static final String CONFIG_PASSWORD = "password";
protected static final String CONFIG_DEBUG_MODE = "debug";
protected static final String CONFIG_USE_STARTTLS = "useStartTLS";
protected static final String CONFIG_ENABLED_SECURITY_PROTOCOLS = "enabledSecurityProtocols";
protected static final String CONFIG_TIMEOUT = "timeout";
protected static final String CONFIG_CONNECTION_TIMEOUT = "connectiontimeout";
protected Map<String, String> configs;
protected String namespace;
public SMTPMailSender(Map<String, String> configs, String namespace) {
if (namespace == null) {
logger.error("Unable to configure SMTP session due to null namespace.");
return;
}
this.configs = configs;
this.namespace = namespace;
this.sessionProps = configureSessionProperties();
if (StringUtils.isNotBlank(sessionProps.getHost())) {
Properties props = new Properties();
props.put(EmailConstants.MAIL_HOST, sessionProps.getHost());
props.put(EmailConstants.MAIL_PORT, sessionProps.getPort());
props.put(EmailConstants.MAIL_SMTP_AUTH, sessionProps.getUseAuth());
String username = sessionProps.getUsername();
if (username != null) {
props.put(EmailConstants.MAIL_SMTP_USER, username);
}
String protocols = sessionProps.getEnabledSecurityProtocols();
if (StringUtils.isNotBlank(protocols)) {
props.put("mail.smtp.ssl.protocols", protocols);
}
if (sessionProps.getUseAuth()) {
props.put(EmailConstants.MAIL_TRANSPORT_STARTTLS_ENABLE, sessionProps.getUseStartTLS());
}
if (sessionProps.getTimeout() != null) {
props.put(EmailConstants.MAIL_SMTP_TIMEOUT, sessionProps.getTimeout());
}
if (sessionProps.getConnectionTimeout() != null) {
props.put(EmailConstants.MAIL_SMTP_CONNECTIONTIMEOUT, sessionProps.getConnectionTimeout());
}
String password = sessionProps.getPassword();
if (StringUtils.isNotBlank(username) && StringUtils.isNotBlank(password)) {
session = Session.getInstance(props, new Authenticator() {
@Override
protected PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication(username, password);
}
});
} else {
session = Session.getInstance(props);
}
session.setDebug(sessionProps.getDebugMode());
} else {
logger.debug("Unable to instantiate SMTP mail session due to empty or null host.");
}
}
protected String getConfig(String config) {
return this.configs.get(String.format("%s.%s", namespace, config));
}
protected SMTPSessionProperties configureSessionProperties() {
String host = getConfig(CONFIG_HOST);
String port = getConfig(CONFIG_PORT);
String useAuth = getConfig(CONFIG_USE_AUTH);
String username = getConfig(CONFIG_USERNAME);
String password = getConfig(CONFIG_PASSWORD);
String debugMode = getConfig(CONFIG_DEBUG_MODE);
String useStartTLS = getConfig(CONFIG_USE_STARTTLS);
String enabledSecurityProtocols = getConfig(CONFIG_ENABLED_SECURITY_PROTOCOLS);
String timeout = getConfig(CONFIG_TIMEOUT);
String connectionTimeout = getConfig(CONFIG_CONNECTION_TIMEOUT);
SMTPSessionProperties sessionProps = new SMTPSessionProperties();
sessionProps.setHost(host);
sessionProps.setPort(NumberUtils.toInt(port, 25));
sessionProps.setUseAuth(BooleanUtils.toBoolean(useAuth));
sessionProps.setUsername(username);
sessionProps.setPassword(password);
sessionProps.setUseStartTLS(BooleanUtils.toBoolean(useStartTLS));
sessionProps.setEnabledSecurityProtocols(enabledSecurityProtocols);
sessionProps.setDebugMode(BooleanUtils.toBoolean(debugMode));
sessionProps.setTimeout(timeout == null ? null : NumberUtils.toInt(timeout));
sessionProps.setConnectionTimeout(connectionTimeout == null ? null : NumberUtils.toInt(connectionTimeout));
return sessionProps;
}
public boolean sendMail(SMTPMailProperties mailProps) {
if (session == null) {
logger.error("Unable to send mail due to null session.");
return false;
}
try {
SMTPMessage message = createMessage(mailProps);
SMTPTransport smtpTrans = createSmtpTransport();
smtpTrans.connect();
smtpTrans.sendMessage(message, message.getAllRecipients());
smtpTrans.close();
return true;
} catch (MessagingException | UnsupportedEncodingException ex) {
logger.error(String.format("Unable to send mail [%s] to the recipcients [%s].", mailProps.getSubject(), mailProps.getRecipients().toString()), ex);
}
return false;
}
protected SMTPMessage createMessage(SMTPMailProperties mailProps) throws MessagingException, UnsupportedEncodingException {
SMTPMessage message = new SMTPMessage(session);
MailAddress sender = mailProps.getSender();
MailAddress from = mailProps.getFrom();
if (from == null) {
from = sender;
}
message.setSender(new InternetAddress(sender.getAddress(), sender.getPersonal()));
message.setFrom(new InternetAddress(from.getAddress(), from.getPersonal()));
setMailRecipients(message, mailProps.getRecipients(), mailProps.getSubject());
message.setSubject(mailProps.getSubject());
message.setSentDate(mailProps.getSentDate() != null ? mailProps.getSentDate() : new Date());
message.setContent(mailProps.getContent(), mailProps.getContentType());
message.saveChanges();
return message;
}
protected SMTPTransport createSmtpTransport() {
URLName urlName = new URLName("smtp", sessionProps.getHost(), sessionProps.getPort(), null, sessionProps.getUsername(), sessionProps.getPassword());
if (sessionProps.getUseAuth() && !sessionProps.getUseStartTLS()) {
return new SMTPSSLTransport(session, urlName);
}
return new SMTPTransport(session, urlName);
}
protected boolean setMailRecipients(SMTPMessage message, Set<MailAddress> recipients, String subject) throws UnsupportedEncodingException, MessagingException {
for (MailAddress recipient : recipients) {
if (StringUtils.isNotBlank(recipient.getAddress())) {
try {
InternetAddress address = new InternetAddress(recipient.getAddress(), recipient.getPersonal());
message.addRecipient(Message.RecipientType.TO, address);
} catch (MessagingException ex) {
logger.error(String.format("Unable to create InternetAddres for address [%s].", recipient), ex);
}
}
}
if (recipients.isEmpty() || message.getAllRecipients().length == 0) {
logger.error("Unable to send mail due to empty list of recipients.");
logger.debug(String.format("Unable to send message [%s].", subject));
return false;
}
return true;
}
}

View File

@ -0,0 +1,113 @@
/*
*
* 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 org.apache.cloudstack.utils.mailing;
public class SMTPSessionProperties {
private String host;
private int port;
private Boolean useAuth;
private String username;
private String password;
private Boolean useStartTLS;
private String enabledSecurityProtocols;
private Boolean debugMode;
private Integer timeout;
private Integer connectionTimeout;
public SMTPSessionProperties() {
}
public String getHost() {
return host;
}
public void setHost(String host) {
this.host = host;
}
public int getPort() {
return port;
}
public void setPort(int port) {
this.port = port;
}
public Boolean getUseAuth() {
return useAuth;
}
public void setUseAuth(Boolean useAuth) {
this.useAuth = useAuth;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public Boolean getUseStartTLS() {
return useStartTLS;
}
public void setUseStartTLS(Boolean useStartTLS) {
this.useStartTLS = useStartTLS;
}
public String getEnabledSecurityProtocols() {
return enabledSecurityProtocols;
}
public void setEnabledSecurityProtocols(String enabledSecurityProtocols) {
this.enabledSecurityProtocols = enabledSecurityProtocols;
}
public Boolean getDebugMode() {
return debugMode;
}
public void setDebugMode(Boolean debugMode) {
this.debugMode = debugMode;
}
public Integer getTimeout() {
return timeout;
}
public void setTimeout(Integer timeout) {
this.timeout = timeout;
}
public Integer getConnectionTimeout() {
return connectionTimeout;
}
public void setConnectionTimeout(Integer connectionTimeout) {
this.connectionTimeout = connectionTimeout;
}
}

View File

@ -0,0 +1,617 @@
/*
*
* 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 org.apache.cloudstack.utils.mailing;
import com.sun.mail.smtp.SMTPMessage;
import com.sun.mail.smtp.SMTPTransport;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import javax.mail.Address;
import javax.mail.MessagingException;
import javax.mail.Session;
import javax.mail.internet.MimeMessage;
import junit.framework.TestCase;
import org.apache.commons.lang3.time.DateUtils;
import org.apache.commons.mail.EmailConstants;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mockito;
import org.mockito.runners.MockitoJUnitRunner;
@RunWith(MockitoJUnitRunner.class)
public class SMTPMailSenderTest extends TestCase {
private SMTPMailSender smtpMailSender;
private Map<String, String> configsMock = Mockito.mock(Map.class);
private String namespace = "test";
private String enabledProtocols = "mail.smtp.ssl.protocols";
@Before
public void before() {
smtpMailSender = new SMTPMailSender(configsMock, namespace);
}
private String getConfigName(String config) {
return String.format("%s.%s", namespace, config);
}
@Test
public void validateSetSessionPropertiesUseStartTLSTrue() {
Map<String, String> configs = new HashMap<>();
configs.put(getConfigName(SMTPMailSender.CONFIG_USE_STARTTLS), "true");
smtpMailSender.configs = configs;
SMTPSessionProperties props = smtpMailSender.configureSessionProperties();
assertTrue(props.getUseStartTLS());
}
@Test
public void validateSetSessionPropertiesUseStartTLSFalse() {
Map<String, String> configs = new HashMap<>();
configs.put(getConfigName(SMTPMailSender.CONFIG_USE_STARTTLS), "false");
smtpMailSender.configs = configs;
SMTPSessionProperties props = smtpMailSender.configureSessionProperties();
assertFalse(props.getUseStartTLS());
}
@Test
public void validateSetSessionPropertiesUseStartTLSUndefinedUseDefaultFalse() {
SMTPMailSender smtpMailSender = new SMTPMailSender(configsMock, namespace);
SMTPSessionProperties props = smtpMailSender.configureSessionProperties();
assertFalse(props.getUseStartTLS());
}
@Test
public void validateSetSessionPropertiesUseAuthTrue() {
Map<String, String> configs = new HashMap<>();
configs.put(getConfigName(SMTPMailSender.CONFIG_USE_AUTH), "true");
smtpMailSender.configs = configs;
SMTPSessionProperties props = smtpMailSender.configureSessionProperties();
assertTrue(props.getUseAuth());
}
@Test
public void validateSetSessionPropertiesUseAuthFalse() {
Map<String, String> configs = new HashMap<>();
configs.put(getConfigName(SMTPMailSender.CONFIG_USE_AUTH), "false");
smtpMailSender.configs = configs;
SMTPSessionProperties props = smtpMailSender.configureSessionProperties();
assertFalse(props.getUseAuth());
}
@Test
public void validateSetSessionPropertiesUseAuthUndefinedUseDefaultFalse() {
SMTPMailSender smtpMailSender = new SMTPMailSender(configsMock, namespace);
SMTPSessionProperties props = smtpMailSender.configureSessionProperties();
assertFalse(props.getUseAuth());
}
@Test
public void validateSetSessionPropertiesDebugModeTrue() {
Map<String, String> configs = new HashMap<>();
configs.put(getConfigName(SMTPMailSender.CONFIG_DEBUG_MODE), "true");
smtpMailSender.configs = configs;
SMTPSessionProperties props = smtpMailSender.configureSessionProperties();
assertTrue(props.getDebugMode());
}
@Test
public void validateSetSessionPropertiesDebugModeFalse() {
Map<String, String> configs = new HashMap<>();
configs.put(getConfigName(SMTPMailSender.CONFIG_DEBUG_MODE), "false");
smtpMailSender.configs = configs;
SMTPSessionProperties props = smtpMailSender.configureSessionProperties();
assertFalse(props.getDebugMode());
}
@Test
public void validateSetSessionPropertiesDebugModeUndefinedUseDefaultFalse() {
SMTPMailSender smtpMailSender = new SMTPMailSender(configsMock, namespace);
SMTPSessionProperties props = smtpMailSender.configureSessionProperties();
assertFalse(props.getDebugMode());
}
@Test
public void validateSMTPMailSenderConstructorHostDefinedAsNullNoSessionCreated() {
SMTPMailSender smtpMailSender = new SMTPMailSender(new HashMap<>(), namespace);
assertNull(smtpMailSender.sessionProps.getHost());
assertNull(smtpMailSender.session);
}
@Test
public void validateSMTPMailSenderConstructorHostDefinedAsEmptyNoSessionCreated() {
Map<String, String> configs = new HashMap<>();
String host = "";
configs.put(getConfigName(SMTPMailSender.CONFIG_HOST), host);
SMTPMailSender smtpMailSender = new SMTPMailSender(configs, namespace);
assertEquals(host, smtpMailSender.sessionProps.getHost());
assertNull(smtpMailSender.session);
}
@Test
public void validateSMTPMailSenderConstructorHostDefinedAsBlankNoSessionCreated() {
Map<String, String> configs = new HashMap<>();
String host = " ";
configs.put(getConfigName(SMTPMailSender.CONFIG_HOST), host);
SMTPMailSender smtpMailSender = new SMTPMailSender(configs, namespace);
assertEquals(host, smtpMailSender.sessionProps.getHost());
assertNull(smtpMailSender.session);
}
@Test
public void validateSMTPMailSenderConstructorHostDefinedSessionCreated() {
Map<String, String> configs = new HashMap<>();
String host = "smtp.acme.org";
configs.put(getConfigName(SMTPMailSender.CONFIG_HOST), host);
SMTPMailSender smtpMailSender = new SMTPMailSender(configs, namespace);
assertEquals(host, smtpMailSender.sessionProps.getHost());
assertNotNull(smtpMailSender.session);
}
private Map<String, String> getConfigsWithHost() {
Map<String, String> configs = new HashMap<>();
String host = "smtp.acme.org";
configs.put(getConfigName(SMTPMailSender.CONFIG_HOST), host);
return configs;
}
@Test
public void validateSMTPMailSenderConstructorPortUndefinedUseDefault25() {
Map<String, String> configs = getConfigsWithHost();
SMTPMailSender smtpMailSender = new SMTPMailSender(configs, namespace);
assertEquals(25, smtpMailSender.sessionProps.getPort());
}
@Test
public void validateSMTPMailSenderConstructorPortDefined() {
Map<String, String> configs = getConfigsWithHost();
int port = 465;
configs.put(getConfigName(SMTPMailSender.CONFIG_PORT), String.valueOf(port));
SMTPMailSender smtpMailSender = new SMTPMailSender(configs, namespace);
assertEquals(port, smtpMailSender.sessionProps.getPort());
}
@Test
public void validateSMTPMailSenderConstructorWithTimeoutUndefined() {
Map<String, String> configs = getConfigsWithHost();
SMTPMailSender smtpMailSender = new SMTPMailSender(configs, namespace);
assertNull(smtpMailSender.sessionProps.getTimeout());
}
@Test
public void validateSMTPMailSenderConstructorWithTimeoutDefined() {
Map<String, String> configs = getConfigsWithHost();
Integer timeout = 12345;
configs.put(getConfigName(SMTPMailSender.CONFIG_TIMEOUT), String.valueOf(timeout));
SMTPMailSender smtpMailSender = new SMTPMailSender(configs, namespace);
assertEquals(timeout, smtpMailSender.sessionProps.getTimeout());
}
@Test
public void validateSMTPMailSenderConstructorWithConnectionTimeoutUndefined() {
Map<String, String> configs = getConfigsWithHost();
SMTPMailSender smtpMailSender = new SMTPMailSender(configs, namespace);
assertNull(smtpMailSender.sessionProps.getConnectionTimeout());
}
@Test
public void validateSMTPMailSenderConstructorWithConnectionTimeoutDefined() {
Map<String, String> configs = getConfigsWithHost();
Integer connectionTimeout = 12345;
configs.put(getConfigName(SMTPMailSender.CONFIG_CONNECTION_TIMEOUT), String.valueOf(connectionTimeout));
SMTPMailSender smtpMailSender = new SMTPMailSender(configs, namespace);
assertEquals(connectionTimeout, smtpMailSender.sessionProps.getConnectionTimeout());
}
@Test
public void validateSMTPMailSenderConstructorWithUsernameUndefined() {
Map<String, String> configs = getConfigsWithHost();
SMTPMailSender smtpMailSender = new SMTPMailSender(configs, namespace);
assertNull(smtpMailSender.sessionProps.getUsername());
}
@Test
public void validateSMTPMailSenderConstructorWithUsernameDefinedAsEmpty() {
Map<String, String> configs = getConfigsWithHost();
String username = "";
configs.put(getConfigName(SMTPMailSender.CONFIG_USERNAME), username);
SMTPMailSender smtpMailSender = new SMTPMailSender(configs, namespace);
assertNotNull(smtpMailSender.sessionProps.getUsername());
assertEquals(username, smtpMailSender.session.getProperties().get(EmailConstants.MAIL_SMTP_USER));
}
@Test
public void validateSMTPMailSenderConstructorWithUsernameDefinedAsBlank() {
Map<String, String> configs = getConfigsWithHost();
String username = " ";
configs.put(getConfigName(SMTPMailSender.CONFIG_USERNAME), username);
SMTPMailSender smtpMailSender = new SMTPMailSender(configs, namespace);
assertNotNull(smtpMailSender.sessionProps.getUsername());
assertEquals(username, smtpMailSender.session.getProperties().get(EmailConstants.MAIL_SMTP_USER));
}
@Test
public void validateSMTPMailSenderConstructorWithValidUsername() {
Map<String, String> configs = getConfigsWithHost();
String username = "test@test.com";
configs.put(getConfigName(SMTPMailSender.CONFIG_USERNAME), username);
SMTPMailSender smtpMailSender = new SMTPMailSender(configs, namespace);
assertNotNull(smtpMailSender.sessionProps.getUsername());
assertEquals(username, smtpMailSender.session.getProperties().get(EmailConstants.MAIL_SMTP_USER));
}
@Test
public void validateSMTPMailSenderConstructorWithProtocolsUndefined() {
Map<String, String> configs = getConfigsWithHost();
SMTPMailSender smtpMailSender = new SMTPMailSender(configs, namespace);
assertNull(smtpMailSender.sessionProps.getEnabledSecurityProtocols());
assertNull(smtpMailSender.session.getProperties().get(enabledProtocols));
}
@Test
public void validateSMTPMailSenderConstructorWithProtocolsDefinedAsEmpty() {
Map<String, String> configs = getConfigsWithHost();
String protocols = "";
configs.put(getConfigName(SMTPMailSender.CONFIG_ENABLED_SECURITY_PROTOCOLS), protocols);
SMTPMailSender smtpMailSender = new SMTPMailSender(configs, namespace);
assertEquals(protocols, smtpMailSender.sessionProps.getEnabledSecurityProtocols());
assertNull(smtpMailSender.session.getProperties().get(enabledProtocols));
}
@Test
public void validateSMTPMailSenderConstructorWithProtocolsDefinedAsBlank() {
Map<String, String> configs = getConfigsWithHost();
String protocols = " ";
configs.put(getConfigName(SMTPMailSender.CONFIG_ENABLED_SECURITY_PROTOCOLS), protocols);
SMTPMailSender smtpMailSender = new SMTPMailSender(configs, namespace);
assertEquals(protocols, smtpMailSender.sessionProps.getEnabledSecurityProtocols());
assertNull(smtpMailSender.session.getProperties().get(enabledProtocols));
}
@Test
public void validateSMTPMailSenderConstructorWithValidProtocol() {
Map<String, String> configs = getConfigsWithHost();
String protocols = "TLSv1";
configs.put(getConfigName(SMTPMailSender.CONFIG_ENABLED_SECURITY_PROTOCOLS), protocols);
SMTPMailSender smtpMailSender = new SMTPMailSender(configs, namespace);
assertEquals(protocols, smtpMailSender.sessionProps.getEnabledSecurityProtocols());
assertEquals(protocols, smtpMailSender.session.getProperties().get(enabledProtocols));
}
@Test
public void validateSMTPMailSenderConstructorWithMultipleValidsProtocols() {
Map<String, String> configs = getConfigsWithHost();
String protocols = "TLSv1 TLSv1.2";
configs.put(getConfigName(SMTPMailSender.CONFIG_ENABLED_SECURITY_PROTOCOLS), protocols);
SMTPMailSender smtpMailSender = new SMTPMailSender(configs, namespace);
assertEquals(protocols, smtpMailSender.sessionProps.getEnabledSecurityProtocols());
assertEquals(protocols, smtpMailSender.session.getProperties().get(enabledProtocols));
}
@Test
public void validateSMTPMailSenderConstructorUseAuthFalseUseStartTLSFalseStartTLSEnabledMustBeNull() {
Map<String, String> configs = getConfigsWithHost();
Boolean useAuth = false;
Boolean useStartTLS = false;
configs.put(getConfigName(SMTPMailSender.CONFIG_USE_AUTH), String.valueOf(useAuth));
configs.put(getConfigName(SMTPMailSender.CONFIG_USE_STARTTLS), String.valueOf(useStartTLS));
SMTPMailSender smtpMailSender = new SMTPMailSender(configs, namespace);
assertNull(smtpMailSender.session.getProperties().get(EmailConstants.MAIL_TRANSPORT_STARTTLS_ENABLE));
}
@Test
public void validateSMTPMailSenderConstructorUseAuthFalseUseStartTLSTrueStartTLSEnabledMustBeNull() {
Map<String, String> configs = getConfigsWithHost();
Boolean useAuth = false;
Boolean useStartTLS = true;
configs.put(getConfigName(SMTPMailSender.CONFIG_USE_AUTH), String.valueOf(useAuth));
configs.put(getConfigName(SMTPMailSender.CONFIG_USE_STARTTLS), String.valueOf(useStartTLS));
SMTPMailSender smtpMailSender = new SMTPMailSender(configs, namespace);
assertNull(smtpMailSender.session.getProperties().get(EmailConstants.MAIL_TRANSPORT_STARTTLS_ENABLE));
}
@Test
public void validateSMTPMailSenderConstructorUseAuthTrueUseStartTLSFalseStartTLSEnabledMustBeFalse() {
Map<String, String> configs = getConfigsWithHost();
Boolean useAuth = true;
Boolean useStartTLS = false;
configs.put(getConfigName(SMTPMailSender.CONFIG_USE_AUTH), String.valueOf(useAuth));
configs.put(getConfigName(SMTPMailSender.CONFIG_USE_STARTTLS), String.valueOf(useStartTLS));
SMTPMailSender smtpMailSender = new SMTPMailSender(configs, namespace);
assertFalse((boolean)smtpMailSender.session.getProperties().get(EmailConstants.MAIL_TRANSPORT_STARTTLS_ENABLE));
}
@Test
public void validateSMTPMailSenderConstructorUseAuthTrueUseStartTLSTrueStartTLSEnabledMustBeFalse() {
Map<String, String> configs = getConfigsWithHost();
Boolean useAuth = true;
Boolean useStartTLS = true;
configs.put(getConfigName(SMTPMailSender.CONFIG_USE_AUTH), String.valueOf(useAuth));
configs.put(getConfigName(SMTPMailSender.CONFIG_USE_STARTTLS), String.valueOf(useStartTLS));
SMTPMailSender smtpMailSender = new SMTPMailSender(configs, namespace);
assertTrue((boolean)smtpMailSender.session.getProperties().get(EmailConstants.MAIL_TRANSPORT_STARTTLS_ENABLE));
}
@Test
public void validateSMTPMailSenderCreateMessageFromDefinedAsNull() throws MessagingException, UnsupportedEncodingException {
smtpMailSender = smtpMailSender = Mockito.spy(smtpMailSender);
SMTPMailProperties mailProps = new SMTPMailProperties();
mailProps.setSender(new MailAddress("test@test.com"));
mailProps.setContent("A simple test");
mailProps.setContentType("text/plain");
Mockito.doReturn(true).when(smtpMailSender).setMailRecipients(Mockito.any(SMTPMessage.class), Mockito.any(), Mockito.any());
SMTPMessage message = smtpMailSender.createMessage(mailProps);
assertEquals("\"test@test.com\" <test@test.com>", message.getFrom()[0].toString());
}
@Test
public void validateSMTPMailSenderCreateMessageFromDefined() throws MessagingException, UnsupportedEncodingException {
smtpMailSender = smtpMailSender = Mockito.spy(smtpMailSender);
SMTPMailProperties mailProps = new SMTPMailProperties();
mailProps.setSender(new MailAddress("test@test.com"));
mailProps.setFrom(new MailAddress("test2@test2.com", "TEST2"));
mailProps.setContent("A simple test");
mailProps.setContentType("text/plain");
Mockito.doReturn(true).when(smtpMailSender).setMailRecipients(Mockito.any(SMTPMessage.class), Mockito.any(), Mockito.any());
SMTPMessage message = smtpMailSender.createMessage(mailProps);
assertEquals("TEST2 <test2@test2.com>", message.getFrom()[0].toString());
}
@Test
public void validateSMTPMailSenderCreateMessageSentDateDefined() throws MessagingException, UnsupportedEncodingException {
smtpMailSender = smtpMailSender = Mockito.spy(smtpMailSender);
SMTPMailProperties mailProps = new SMTPMailProperties();
mailProps.setSender(new MailAddress("test@test.com"));
mailProps.setContent("A simple test");
mailProps.setContentType("text/plain");
Calendar cal = Calendar.getInstance();
cal.setTime(new Date());
cal.set(Calendar.YEAR, 2015);
cal.set(Calendar.MONTH, 1);
cal.set(Calendar.DAY_OF_MONTH, 1);
mailProps.setSentDate(cal.getTime());
Mockito.doReturn(true).when(smtpMailSender).setMailRecipients(Mockito.any(SMTPMessage.class), Mockito.any(), Mockito.any());
SMTPMessage message = smtpMailSender.createMessage(mailProps);
assertTrue(DateUtils.truncatedEquals(cal.getTime(), message.getSentDate(), Calendar.SECOND));
}
@Test
public void validateSMTPMailSenderCreateMessageSubjectContentAndContentTypeDefined() throws MessagingException, UnsupportedEncodingException, IOException {
smtpMailSender = smtpMailSender = Mockito.spy(smtpMailSender);
SMTPMailProperties mailProps = new SMTPMailProperties();
String subject = "A TEST";
String content = "A simple test";
String contentType = "text/plain;charset=utf8";
mailProps.setSender(new MailAddress("test@test.com"));
mailProps.setSubject(subject);
mailProps.setContent(content);
mailProps.setContentType(contentType);
Mockito.doReturn(true).when(smtpMailSender).setMailRecipients(Mockito.any(SMTPMessage.class), Mockito.any(), Mockito.any());
SMTPMessage message = smtpMailSender.createMessage(mailProps);
assertEquals(subject, message.getSubject());
assertEquals(content, message.getContent());
assertEquals(contentType, message.getContentType());
}
@Test
public void setMailRecipientsTest() throws UnsupportedEncodingException, MessagingException {
SMTPMessage messageMock = new SMTPMessage(Mockito.mock(MimeMessage.class));
Set<MailAddress> recipients = new HashSet<>();
recipients.add(new MailAddress(null));
recipients.add(new MailAddress(""));
recipients.add(new MailAddress(" "));
recipients.add(new MailAddress("smtp.acme.org"));
recipients.add(new MailAddress("smtp.acme2.org", "Coyote"));
boolean returnOfSetEmail = smtpMailSender.setMailRecipients(messageMock, recipients, "A simple test");
Address[] allRecipients = messageMock.getAllRecipients();
int expectedNumberOfValidRecipientsConfigured = 2;
assertEquals(expectedNumberOfValidRecipientsConfigured, allRecipients.length);
assertEquals("\"smtp.acme.org\" <smtp.acme.org>", allRecipients[0].toString());
assertEquals("Coyote <smtp.acme2.org>", allRecipients[1].toString());
assertTrue(returnOfSetEmail);
}
@Test
public void setMailRecipientsTestOnlyInvalidEmailSettings() throws UnsupportedEncodingException, MessagingException {
SMTPMessage messageMock = new SMTPMessage(Mockito.mock(MimeMessage.class));
messageMock = messageMock = Mockito.spy(messageMock);
Mockito.doReturn(new Address[0]).when(messageMock).getAllRecipients();
Set<MailAddress> recipients = new HashSet<>();
recipients.add(new MailAddress(null));
recipients.add(new MailAddress(""));
recipients.add(new MailAddress(" "));
boolean returnOfSetEmail = smtpMailSender.setMailRecipients(messageMock, recipients, "A simple test");
Address[] allRecipients = messageMock.getAllRecipients();
int expectedNumberOfValidRecipientsConfigured = 0;
assertEquals(expectedNumberOfValidRecipientsConfigured, allRecipients.length);
assertFalse(returnOfSetEmail);
}
@Test
public void validateSMTPMailSenderSendMailWithNullSession() {
SMTPMailProperties mailProps = new SMTPMailProperties();
boolean returnOfSendMail = smtpMailSender.sendMail(mailProps);
assertFalse(returnOfSendMail);
}
@Test
public void validateSMTPMailSenderSendMailWithValidSession() throws MessagingException, UnsupportedEncodingException {
smtpMailSender = smtpMailSender = Mockito.spy(smtpMailSender);
SMTPMailProperties mailProps = new SMTPMailProperties();
smtpMailSender.session = Session.getDefaultInstance(Mockito.mock(Properties.class));
Mockito.doReturn(Mockito.mock(SMTPMessage.class)).when(smtpMailSender).createMessage(Mockito.any(SMTPMailProperties.class));
Mockito.doReturn(Mockito.mock(SMTPTransport.class)).when(smtpMailSender).createSmtpTransport();
boolean returnOfSendMail = smtpMailSender.sendMail(mailProps);
assertTrue(returnOfSendMail);
}
@Test
public void validateSMTPMailSenderGetConfigPropertyUndefinedMustReturnNull() {
smtpMailSender = smtpMailSender = Mockito.spy(smtpMailSender);
String returnOfPropertyThatDoesNotExist = smtpMailSender.getConfig("test");
assertNull(returnOfPropertyThatDoesNotExist);
}
public void validateSMTPMailSenderGetConfigPropertyDefinedMustReturnIt() {
smtpMailSender = smtpMailSender = Mockito.spy(smtpMailSender);
Map<String, String> configs = new HashMap<>();
String host = "smtp.acme.org";
configs.put(getConfigName(SMTPMailSender.CONFIG_HOST), host);
smtpMailSender.configs = configs;
String returnOfPropertyThatExist = smtpMailSender.getConfig(getConfigName(SMTPMailSender.CONFIG_HOST));
assertNotNull(returnOfPropertyThatExist);
assertNotNull(host, returnOfPropertyThatExist);
}
}