Reading of OTP from email
Tags: automation, java, testing
Published: 2023-03-07 09:15:38

It is not a rarely case when an OTP is sent to allow users enter an application. And sometimes it is not easy to automate the process of receiving the OPT and using it in your tests.

There are some tools that help with this task like [Mailosaur](https://mailosaur.com/docs/languages/java/) and [Twillio](https://www.twilio.com/resource-center/category/email-api).
Also there are some other solutions.
One of the simplest one is to agree with backend developers accepting some hardcoded OTP on test environment.
Another one is to wait for a push notification about incomming email message with OTP on your mobile device, click it and read from the opened page.

I would like to suggest you one more that works really good for me.

The solution is based on [JavaMail API](https://mvnrepository.com/artifact/com.sun.mail/javax.mail).

So, let's start.

After you added the dependency create a class which reads the OTP:

```
import javax.mail.*;
import javax.mail.internet.ContentType;
import javax.mail.internet.MimeMultipart;
import javax.mail.search.FlagTerm;
import java.io.IOException;
import java.util.Properties;

public class OtpReader {
        private final static String host = "imap.gmail.com";
        private final static String mailStoreType = "imaps";
        private final static String port = "993";
        // email is your email address where email with OTP is sent
        private final static String email = "your.email@gmail.com";
        // password is app password created for the email address above
        private final static String password = "your.app.password";

        public static String getOtp()
        {
            try
            {
                String otp = "";

                // delay to let backend sends email with OTP
                Thread.sleep(10000);

                Properties properties = new Properties();
                properties.put("mail.imap.host", host);
                properties.put("mail.imap.port", port);
                properties.put("mail.imap.starttls.enable", "true");
                properties.put("mail.imap.ssl.trust", host);

                Session emailSession = Session.getDefaultInstance(properties);
                Store store = emailSession.getStore(mailStoreType);
                store.connect(host, email, password);

                Folder inbox = store.getFolder("Inbox");
                inbox.open(Folder.READ_WRITE);
                // all unread emails from Inbox folder is to be in the messages array
                Message[] messages = inbox.search(new FlagTerm(new Flags(Flags.Flag.SEEN), false));

                // go through all the messages
                for (Message singleMessage: messages)
                {
                    // find a message with the same Subject as emails with OTP usually have
                    if (singleMessage.getSubject().equals("Well-known subject"))
                    {
                        singleMessage.setFlag(Flags.Flag.SEEN, true);
                        String messageBody = getMessageBody(singleMessage);
                        String otpPhrase = "Your OTP is ";
                        // find index inside the message body where OTP is written
                        int indexOfOtpStart = messageBody.indexOf(otpPhrase) + otpPhrase.length();
                        // get 6-digit OTP
                        otp = otp + messageBody.substring(indexOfOtpStart, indexOfOtpStart + 6);
                    }
                }
                inbox.close(false);
                store.close();

                return otp;
            }
            catch (Exception e)
            {
                throw new RuntimeException("There are problems with reading emails.");
            }
        }
        private static String getMessageBody(Message message) throws MessagingException, IOException
        {
            String messageBody = "";
            if (message.isMimeType("text/plain"))
            {
                messageBody = message.getContent().toString();
            }
            else if (message.isMimeType("multipart/*"))
            {
                MimeMultipart mimeMultipart = (MimeMultipart) message.getContent();
                messageBody = getTextFromMimeMultipart(mimeMultipart);
            }
            return messageBody;
        }
        private static String getTextFromMimeMultipart(MimeMultipart mimeMultipart) throws IOException, MessagingException
        {
            int count = mimeMultipart.getCount();
            if (count == 0)
                throw new MessagingException("Multipart with no body parts not supported.");
            boolean multipartAlt = new ContentType(mimeMultipart.getContentType()).match("multipart/alternative");
            if (multipartAlt)
                return getTextFromBodyPart(mimeMultipart.getBodyPart(count - 1));
            String result = "";
            for (int i = 0; i < count; i++)
            {
                BodyPart bodyPart = mimeMultipart.getBodyPart(i);
                result += getTextFromBodyPart(bodyPart);
            }
            return result;
        }
        private static String getTextFromBodyPart(BodyPart bodyPart) throws IOException, MessagingException
        {
            String result = "";
            if (bodyPart.isMimeType("text/plain"))
            {
                result = (String) bodyPart.getContent();
            }
            else if (bodyPart.isMimeType("text/html"))
            {
                String html = (String) bodyPart.getContent();
                result = org.jsoup.Jsoup.parse(html).text();
            }
            else if (bodyPart.getContent() instanceof MimeMultipart)
            {
                result = getTextFromMimeMultipart((MimeMultipart)bodyPart.getContent());
            }
            return result;
        }
}
```

However, the let this code working there are some additional preparations:

1. Create a Gmail account or use an existing one.
2. Open Forwarding and POP/IMAP Settings for this account and enable IMAP.
3. Open Account Security Settings and turn on 2-Step Verification.
4. In the Security Settings go to the Signing in to Google >> App Passwords and create an app password with some custom app name.
5. Use these email and app password in the OptReader class.

Happy testing!