This is an automated email from the ASF dual-hosted git repository.

dahn pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/cloudstack.git


The following commit(s) were added to refs/heads/main by this push:
     new e962f0f  Unify SMTP mail sending (#4954)
e962f0f is described below

commit e962f0f27181a367eb8c9f54f64b995f935a5085
Author: Daniel Augusto Veronezi Salvador 
<[email protected]>
AuthorDate: Tue Jun 15 18:18:26 2021 -0300

    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 <[email protected]>
    
    * Remove copyright line in license header
    
    Co-authored-by: Gabriel Beims Bräscher <[email protected]>
    
    * Remove copyright line in license header
    
    Co-authored-by: Gabriel Beims Bräscher <[email protected]>
    
    * Remove copyright line in license header
    
    Co-authored-by: Gabriel Beims Bräscher <[email protected]>
    
    * Remove copyright line in license header
    
    Co-authored-by: Gabriel Beims Bräscher <[email protected]>
    
    Co-authored-by: Daniel Augusto Veronezi Salvador <[email protected]>
    Co-authored-by: Gabriel Beims Bräscher <[email protected]>
---
 .../cloudstack/quota/QuotaAlertManagerImpl.java    | 149 +----
 .../quota/QuotaAlertManagerImplTest.java           |  14 +-
 .../java/com/cloud/alert/AlertManagerImpl.java     | 275 +++------
 .../com/cloud/projects/ProjectManagerImpl.java     | 152 ++---
 .../com/cloud/usage/UsageAlertManagerImpl.java     | 228 ++------
 utils/pom.xml                                      |   9 +
 .../cloudstack/utils/mailing/MailAddress.java      |  63 +++
 .../utils/mailing/SMTPMailProperties.java          |  89 +++
 .../cloudstack/utils/mailing/SMTPMailSender.java   | 231 ++++++++
 .../utils/mailing/SMTPSessionProperties.java       | 113 ++++
 .../utils/mailing/SMTPMailSenderTest.java          | 617 +++++++++++++++++++++
 11 files changed, 1336 insertions(+), 604 deletions(-)

diff --git 
a/framework/quota/src/main/java/org/apache/cloudstack/quota/QuotaAlertManagerImpl.java
 
b/framework/quota/src/main/java/org/apache/cloudstack/quota/QuotaAlertManagerImpl.java
index 019420c..924d9c4 100644
--- 
a/framework/quota/src/main/java/org/apache/cloudstack/quota/QuotaAlertManagerImpl.java
+++ 
b/framework/quota/src/main/java/org/apache/cloudstack/quota/QuotaAlertManagerImpl.java
@@ -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;
-
-        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;
-
-            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);
-                }
+    protected void sendQuotaAlert(List<String> emails, String subject, String 
body) {
+        SMTPMailProperties mailProperties = new SMTPMailProperties();
 
-                if (smtpUseAuth) {
-                    smtpProps.put("mail.smtp.starttls.enable", 
smtpUseStartTLS);
-                }
+        mailProperties.setSender(new MailAddress(senderAddress));
+        mailProperties.setSubject(subject);
+        mailProperties.setContent(body);
+        mailProperties.setContentType("text/html; charset=utf-8");
 
-                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));
-
-            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);
-                    }
-                }
-            }
+        mailProperties.setRecipients(addresses);
 
-            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);
     }
+
 }
diff --git 
a/framework/quota/src/test/java/org/apache/cloudstack/quota/QuotaAlertManagerImplTest.java
 
b/framework/quota/src/test/java/org/apache/cloudstack/quota/QuotaAlertManagerImplTest.java
index 88485b9..95033cc 100644
--- 
a/framework/quota/src/test/java/org/apache/cloudstack/quota/QuotaAlertManagerImplTest.java
+++ 
b/framework/quota/src/test/java/org/apache/cloudstack/quota/QuotaAlertManagerImplTest.java
@@ -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
diff --git a/server/src/main/java/com/cloud/alert/AlertManagerImpl.java 
b/server/src/main/java/com/cloud/alert/AlertManagerImpl.java
index d48f2a3..99200f41c 100644
--- a/server/src/main/java/com/cloud/alert/AlertManagerImpl.java
+++ b/server/src/main/java/com/cloud/alert/AlertManagerImpl.java
@@ -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");
+
+        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));
 
-        _emailAlert = new EmailAlert(emailAddresses, smtpHost, smtpPort, 
smtpConnectionTimeout, smtpTimeout, useAuth, smtpUsername, smtpPassword, 
emailSender, smtpDebug);
+        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) {
diff --git a/server/src/main/java/com/cloud/projects/ProjectManagerImpl.java 
b/server/src/main/java/com/cloud/projects/ProjectManagerImpl.java
index 88ad0c2..7cb4674 100644
--- a/server/src/main/java/com/cloud/projects/ProjectManagerImpl.java
+++ b/server/src/main/java/com/cloud/projects/ProjectManagerImpl.java
@@ -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
diff --git a/usage/src/main/java/com/cloud/usage/UsageAlertManagerImpl.java 
b/usage/src/main/java/com/cloud/usage/UsageAlertManagerImpl.java
index fd8c7c0..3ee64e6 100644
--- a/usage/src/main/java/com/cloud/usage/UsageAlertManagerImpl.java
+++ b/usage/src/main/java/com/cloud/usage/UsageAlertManagerImpl.java
@@ -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);
         }
-    }
-
-    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;
-            }
+        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;
         }
 
-        // 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);
-            }
+        SMTPMailProperties mailProps = new SMTPMailProperties();
+        mailProps.setSender(new MailAddress(senderAddress));
+        mailProps.setSubject(subject);
+        mailProps.setContent(content);
+        mailProps.setContentType("text/plain");
 
-            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();
-            }
+        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);
-                if (alert != null) {
-                    AlertVO updatedAlert = _alertDao.createForUpdate();
-                    updatedAlert.setResolved(new Date());
-                    _alertDao.update(alert.getId(), updatedAlert);
-                }
+        mailProps.setRecipients(addresses);
+        mailSender.sendMail(mailProps);
+    }
+
+    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;
         }
     }
diff --git a/utils/pom.xml b/utils/pom.xml
index 8f42567..347ba5b 100755
--- a/utils/pom.xml
+++ b/utils/pom.xml
@@ -185,6 +185,15 @@
             <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>
         </dependency>
diff --git 
a/utils/src/main/java/org/apache/cloudstack/utils/mailing/MailAddress.java 
b/utils/src/main/java/org/apache/cloudstack/utils/mailing/MailAddress.java
new file mode 100644
index 0000000..aab51fe
--- /dev/null
+++ b/utils/src/main/java/org/apache/cloudstack/utils/mailing/MailAddress.java
@@ -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();
+    }
+
+}
diff --git 
a/utils/src/main/java/org/apache/cloudstack/utils/mailing/SMTPMailProperties.java
 
b/utils/src/main/java/org/apache/cloudstack/utils/mailing/SMTPMailProperties.java
new file mode 100644
index 0000000..ef5d895
--- /dev/null
+++ 
b/utils/src/main/java/org/apache/cloudstack/utils/mailing/SMTPMailProperties.java
@@ -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;
+    }
+
+}
diff --git 
a/utils/src/main/java/org/apache/cloudstack/utils/mailing/SMTPMailSender.java 
b/utils/src/main/java/org/apache/cloudstack/utils/mailing/SMTPMailSender.java
new file mode 100644
index 0000000..42497eb
--- /dev/null
+++ 
b/utils/src/main/java/org/apache/cloudstack/utils/mailing/SMTPMailSender.java
@@ -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;
+    }
+
+}
diff --git 
a/utils/src/main/java/org/apache/cloudstack/utils/mailing/SMTPSessionProperties.java
 
b/utils/src/main/java/org/apache/cloudstack/utils/mailing/SMTPSessionProperties.java
new file mode 100644
index 0000000..cc7023d
--- /dev/null
+++ 
b/utils/src/main/java/org/apache/cloudstack/utils/mailing/SMTPSessionProperties.java
@@ -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;
+    }
+
+}
diff --git 
a/utils/src/test/java/org/apache/cloudstack/utils/mailing/SMTPMailSenderTest.java
 
b/utils/src/test/java/org/apache/cloudstack/utils/mailing/SMTPMailSenderTest.java
new file mode 100644
index 0000000..bb2290b
--- /dev/null
+++ 
b/utils/src/test/java/org/apache/cloudstack/utils/mailing/SMTPMailSenderTest.java
@@ -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 = "[email protected]";
+        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("[email protected]"));
+        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("\"[email protected]\" <[email protected]>", 
message.getFrom()[0].toString());
+    }
+
+    @Test
+    public void validateSMTPMailSenderCreateMessageFromDefined() throws 
MessagingException, UnsupportedEncodingException {
+        smtpMailSender = smtpMailSender = Mockito.spy(smtpMailSender);
+
+        SMTPMailProperties mailProps = new SMTPMailProperties();
+
+        mailProps.setSender(new MailAddress("[email protected]"));
+        mailProps.setFrom(new MailAddress("[email protected]", "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 <[email protected]>", 
message.getFrom()[0].toString());
+    }
+
+    @Test
+    public void validateSMTPMailSenderCreateMessageSentDateDefined() throws 
MessagingException, UnsupportedEncodingException {
+        smtpMailSender = smtpMailSender = Mockito.spy(smtpMailSender);
+
+        SMTPMailProperties mailProps = new SMTPMailProperties();
+
+        mailProps.setSender(new MailAddress("[email protected]"));
+        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("[email protected]"));
+        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);
+    }
+}

Reply via email to