Sending Emails for Email-Verification from SUSI Server

In this blog post, I will explain how emails are sent from the SUSI server to validate Email IDs.

Whenever a user creates an account on SUSI.AI Client we are required to check the email and verify that email in order to activate it. By doing so we can reduce the number of spam and fake accounts.

//After all the imports 
public class EmailHandler {

This is a regex expression for validating the user input on the server side. This expression checks that the email address entered must match something similar to [email protected]

    public static final String EMAIL_PATTERN = "^[_A-Za-z0-9-\\+]+(\\.[_A-Za-z0-9-]+)*@"
            + "[A-Za-z0-9-]+(\\.[A-Za-z0-9]+)*(\\.[A-Za-z]{2,})$";
   

This function below sends an email to the parameter addressTo. “subject” is the email subject and text the content of the Mail. The content of the mail could be plain text or HTML. Using HTML in emails helps to make clickable links and more formatted emails.

    public static void sendEmail(@Nonnull String addressTo, @Nonnull String subject, @Nonnull String text) throws Exception {
        String senderEmail = DAO.getConfig("smtp.sender.email", null);
        String displayname = DAO.getConfig("smtp.sender.displayname", null);
        sendEmail(senderEmail, displayname, addressTo, subject, text);
    }

This function below is an example of Function overloading. This is used when a displayName parameter is passed and then a mail is sent with the name of the user.

For applications using SSL/TLS endpoints whose certificates are not signed by a public CA, it is required to tell applications to trust self-signed certs.

 public static void sendEmail(String senderEmail, String displayname, @Nonnull String addressTo, @Nonnull String subject, @Nonnull String text) throws Exception {
        
        if (!"true".equals(DAO.getConfig("smtp.mails.enabled", "false"))) {
            throw new Exception("Mail sending disabled");
        }

        String username = DAO.getConfig("smtp.sender.username", null);
        String password = DAO.getConfig("smtp.sender.password", null);
        String hostname = DAO.getConfig("smtp.host.name", null);
        String encryption = DAO.getConfig("smtp.host.encryption", null);
        boolean disableCertChecking = DAO.getConfig("smtp.trustselfsignedcerts", false);

Here are some null checks so that server should not crash unexpectedly. Here we are checking for Sender Email, password and the hostname. These are used to generate the SMTP configuration for sending emails.

if(senderEmail == null || password == null || hostname == null){
            throw new Exception("Invalid SMTP configuration");
        }

Now we check the regex of the previously declared regex expression for validating the email addresses. This is done using the pattern that we defined at the very beginning of this file.

Pattern pattern = Pattern.compile(EMAIL_PATTERN);
        if (!new TimeoutMatcher(pattern.matcher(addressTo)).matches()) {
            throw new Exception("Invalid email ID");
        }
        if (!new TimeoutMatcher(pattern.matcher(senderEmail)).matches()) {
            throw new Exception("Invalid sender ID");
        }

Finally, the email is composed here with all the headers, subject and text. The Mime Message and Transport are a part of javax.mail library.

You can install that by adding the below line in you build.gradle file.

compile group: 'com.sun.mail', name: 'javax.mail', version: '1.+'
    MimeMessage message = new MimeMessage(session);
        message.addHeader("Content-type", "text/HTML; charset=UTF-8");
        message.addHeader("format", "flowed");
        message.addHeader("Content-Transfer-Encoding", "8bit");
        message.setSentDate(new Date());
        message.setReplyTo(new Address[]{new InternetAddress(senderEmail, displayname)});
        message.setFrom(new InternetAddress(senderEmail, displayname));
        message.setRecipients(Message.RecipientType.TO, InternetAddress.parse(addressTo, false));
        message.setSubject(subject, "UTF-8");
        message.setText(text, "UTF-8");

Then we call the send method to finally send an email to the user. This sends the “message” that we composed above with all out headers, encodings, dates etc.

    Transport.send(message);
        Log.getLog().info("Successfully send mail to " + addressTo);
    }

This is a pretty old technique to validate email addresses. Mail addresses cannot be created and doctored too quickly. Also, email address verification is not the only way to verify users. This can be totally replaced by using social logins.

References

SUSI Server : https://github.com/fossasia/susi_server/

Tutorial: https://www.javatpoint.com/java-mail-api-tutorial

Official Docs: https://javaee.github.io/javamail/