Monday, November 21, 2016

Java read email from google using oauth2 and parse email

Read Email From Google Account


package com.google_api;

import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;

/**
 * Created by pritom on 21/11/2016.
 */
public class JavaReadEmail extends JavaRawEmailParser {
    public static void main(String[] args) throws Exception {
        String accessToken = getAccessToken();
        String userID = "118224582562607576118"; /* From google profile */
        String messageID = "158855e85a035ed1";
        String url = "https://www.googleapis.com/gmail/v1/users/";
        url += userID + "/messages/" + messageID + "?format=raw";
        url += "&access_token=" + accessToken;

        HttpURLConnection connection = (HttpURLConnection) new URL(url).openConnection();
        connection.setRequestMethod("GET");
        connection.setRequestProperty("Content-Type", "application/json");

        int httpCode = connection.getResponseCode();
        String responseMessage = connection.getResponseMessage(), httpResponse = "";
        InputStream is = null;
        if (httpCode >= 200 && httpCode <= 299) {
            is = connection.getInputStream();
        }
        else {
            is = connection.getErrorStream();
        }

        Writer writer5 = new StringWriter();
        char[] buffer = new char[1024];
        Reader reader = new BufferedReader(new InputStreamReader(is, "UTF-8"));
        int n;
        while ((n = reader.read(buffer)) != -1) {
            writer5.write(buffer, 0, n);
        }
        httpResponse = writer5.toString();
        println(httpResponse);

        String snippet = httpResponse.substring(httpResponse.indexOf("\"snippet\":") + 12);
        snippet = snippet.substring(0, snippet.indexOf("\n") - 2).trim();
        println("Snippet=" + snippet);

        String raw = httpResponse.substring(httpResponse.indexOf("\"raw\":") + 8);
        raw = raw.substring(0, raw.indexOf("\n") - 2).trim();

        parse(raw);
    }

    private static String getAccessToken() throws Exception {
        return "return access token from google";
    }
}

Parse Email Received From Google Account


package com.google_api;

import javax.mail.*;
import javax.mail.internet.MimeMessage;
import java.io.BufferedWriter;
import java.io.ByteArrayInputStream;
import java.io.FileWriter;
import java.io.InputStream;
import java.util.*;

/**
 * Created by pritom on 20/11/2016.
 */
public class JavaRawEmailParser {
    private static final String ENCODING = "UTF-8";

    public static void parse(String rawEmail) throws Exception {
        rawEmail = Base64Decoder.decodeBase64(rawEmail);
        Session s = Session.getDefaultInstance(new Properties());
        InputStream is = new ByteArrayInputStream(rawEmail.getBytes(ENCODING));
        MimeMessage mimeMessage = new MimeMessage(s, is);
        Enumeration enumeration = mimeMessage.getAllHeaders();
        while (enumeration.hasMoreElements()) {
            Header header = (Header) enumeration.nextElement();
            if (!header.getName().contains("Received")) {
                println(header.getName() + " == " + toSingleLine(header.getValue()));
            }
        }
        Map output = processMultipart((Multipart) mimeMessage.getContent());
        for (Object key : output.keySet().toArray()) {
            println("Key=<<" + key + ">> == " + output.get(key));
        }
    }

    private static Map processMultipart(Multipart multipart) throws Exception {
        Map output = new HashMap();
        output.put("html", "");
        output.put("text", "");
        List attachments = new ArrayList();

        for(int i = 0; i < multipart.getCount(); i++) {
            Map result = processBodyPart(multipart.getBodyPart(i));
            if (result != null) {
                if (result.containsKey("type")) {
                    if (result.get("type").toString().equalsIgnoreCase("html")) {
                        output.put("html", result.get("content").toString());
                    }
                    else if (result.get("type").toString().equalsIgnoreCase("text")) {
                        output.put("text", result.get("content").toString());
                    }
                    else if (result.get("type").toString().equalsIgnoreCase("attachment")) {
                        attachments.add(result);
                    }
                }
                if (result.containsKey("html")) {
                    output.put("html", result.get("html").toString());
                }
                if (result.containsKey("text")) {
                    output.put("text", result.get("text").toString());
                }
                if (result.containsKey("attachments")) {
                    List thisAttachments = (List) result.get("attachments");
                    for (int i2 = 0; i2 < thisAttachments.size(); i2++) {
                        attachments.add(thisAttachments.get(i2));
                    }
                }
            }
        }
        output.put("attachments", attachments);

        return output;
    }

    private static Map processBodyPart(BodyPart bodyPart) throws Exception {
        if(bodyPart.isMimeType("text/html") && bodyPart.getFileName() == null) {
            Map data = new HashMap();
            data.put("type", "html");
            data.put("content", bodyPart.getContent().toString());
            return data;
        }
        else if(bodyPart.isMimeType("text/plain") && bodyPart.getFileName() == null) {
            Map data = new HashMap();
            data.put("type", "text");
            data.put("content", bodyPart.getContent().toString());
            return data;
        }
        else if(Part.ATTACHMENT.equalsIgnoreCase(bodyPart.getDisposition()) && bodyPart.getFileName() != null) {
            Map map = new HashMap();
            map.put("type", "attachment");
            map.put("fileName", bodyPart.getFileName());
            map.put("fileType", bodyPart.getContentType().substring(0, bodyPart.getContentType().indexOf(";")));
            map.put("mimeBodyPart", bodyPart);
            return map;
        }
        else if(bodyPart.getContentType().contains("multipart")) {
            Map o = processMultipart((Multipart) bodyPart.getContent());
            return o;
        }
        return null;
    }

    private static String toSingleLine(String str) throws Exception {
        return str.replaceAll("\\s+", " ");
    }

    private static void writeToFile(String location, String content) throws Exception {
        BufferedWriter out = new BufferedWriter(new FileWriter(location));
        out.write(content);
        out.close();
    }

    protected static void println(Object o) {
        System.out.println("" + o);
    }
}

Decode Util Class


package com.google_api;

/**
 * Created by pritom on 20/11/2016.
 */
public class Base64Decoder {
    private static final String ENCODING = "UTF-8";
    private static final byte[] CHUNK_SEPARATOR = new byte[]{(byte)13, (byte)10};
    private static final byte[] DECODE_TABLE = new byte[]{
            (byte)-1, (byte)-1, (byte)-1, (byte)-1, (byte)-1, (byte)-1, (byte)-1, (byte)-1, (byte)-1, (byte)-1,
            (byte)-1, (byte)-1, (byte)-1, (byte)-1, (byte)-1, (byte)-1, (byte)-1, (byte)-1, (byte)-1, (byte)-1,
            (byte)-1, (byte)-1, (byte)-1, (byte)-1, (byte)-1, (byte)-1, (byte)-1, (byte)-1, (byte)-1, (byte)-1,
            (byte)-1, (byte)-1, (byte)-1, (byte)-1, (byte)-1, (byte)-1, (byte)-1, (byte)-1, (byte)-1, (byte)-1,
            (byte)-1, (byte)-1, (byte)-1, (byte)62, (byte)-1, (byte)62, (byte)-1, (byte)63, (byte)52, (byte)53,
            (byte)54, (byte)55, (byte)56, (byte)57, (byte)58, (byte)59, (byte)60, (byte)61, (byte)-1, (byte)-1,
            (byte)-1, (byte)-1, (byte)-1, (byte)-1, (byte)-1, (byte)0, (byte)1, (byte)2, (byte)3, (byte)4, (byte)5,
            (byte)6, (byte)7, (byte)8, (byte)9, (byte)10, (byte)11, (byte)12, (byte)13, (byte)14, (byte)15, (byte)16,
            (byte)17, (byte)18, (byte)19, (byte)20, (byte)21, (byte)22, (byte)23, (byte)24, (byte)25, (byte)-1,
            (byte)-1, (byte)-1, (byte)-1, (byte)63, (byte)-1, (byte)26, (byte)27, (byte)28, (byte)29, (byte)30,
            (byte)31, (byte)32, (byte)33, (byte)34, (byte)35, (byte)36, (byte)37, (byte)38, (byte)39, (byte)40,
            (byte)41, (byte)42, (byte)43, (byte)44, (byte)45, (byte)46, (byte)47, (byte)48, (byte)49, (byte)50, (byte)51};
    private final byte[] decodeTable;
    private final int decodeSize;
    private int bitWorkArea;
    private byte[] buffer;
    private int pos;
    private int readPos;
    private boolean eof;
    private int modulus;

    public static String decodeBase64(String raw) throws Exception {
        return new String(new Base64Decoder(0, CHUNK_SEPARATOR).decode(raw), ENCODING);
    }

    private Base64Decoder(int lineLength, byte[] lineSeparator) throws Exception {
        super();
        this.decodeTable = DECODE_TABLE;
        int encodeSize;
        if(lineSeparator != null) {
            if(this.containsAlphabetOrPad(lineSeparator)) {
                String sep = newStringUtf8(lineSeparator);
                throw new Exception("lineSeparator must not contain base64 characters: [" + sep + "]");
            }

            if(lineLength > 0) {
                encodeSize = 4 + lineSeparator.length;
                System.arraycopy(lineSeparator, 0, new byte[lineSeparator.length], 0, lineSeparator.length);
            } else {
                encodeSize = 4;
            }
        } else {
            encodeSize = 4;
        }

        this.decodeSize = encodeSize - 1;
    }

    private void decode(byte[] in, int inPos, int inAvail) {
        if(!this.eof) {
            if(inAvail < 0) {
                this.eof = true;
            }

            for(int i = 0; i < inAvail; ++i) {
                this.ensureBufferSize(this.decodeSize);
                byte b = in[inPos++];
                if(b == 61) {
                    this.eof = true;
                    break;
                }

                if(b >= 0 && b < DECODE_TABLE.length) {
                    byte result = DECODE_TABLE[b];
                    if(result >= 0) {
                        this.modulus = (this.modulus + 1) % 4;
                        this.bitWorkArea = (this.bitWorkArea << 6) + result;
                        if(this.modulus == 0) {
                            this.buffer[this.pos++] = (byte)(this.bitWorkArea >> 16 & 255);
                            this.buffer[this.pos++] = (byte)(this.bitWorkArea >> 8 & 255);
                            this.buffer[this.pos++] = (byte)(this.bitWorkArea & 255);
                        }
                    }
                }
            }

            if(this.eof && this.modulus != 0) {
                this.ensureBufferSize(this.decodeSize);
                switch(this.modulus) {
                    case 2:
                        this.bitWorkArea >>= 4;
                        this.buffer[this.pos++] = (byte)(this.bitWorkArea & 255);
                        break;
                    case 3:
                        this.bitWorkArea >>= 2;
                        this.buffer[this.pos++] = (byte)(this.bitWorkArea >> 8 & 255);
                        this.buffer[this.pos++] = (byte)(this.bitWorkArea & 255);
                }
            }

        }
    }

    private boolean isInAlphabet(byte octet) {
        return octet >= 0 && octet < this.decodeTable.length && this.decodeTable[octet] != -1;
    }

    private int available() {
        return this.buffer != null ? this.pos - this.readPos : 0;
    }

    private int getDefaultBufferSize() {
        return 8192;
    }

    private void resizeBuffer() {
        if(this.buffer == null) {
            this.buffer = new byte[this.getDefaultBufferSize()];
            this.pos = 0;
            this.readPos = 0;
        }
        else {
            byte[] b = new byte[this.buffer.length * 2];
            System.arraycopy(this.buffer, 0, b, 0, this.buffer.length);
            this.buffer = b;
        }
    }

    private void ensureBufferSize(int size) {
        if(this.buffer == null || this.buffer.length < this.pos + size) {
            this.resizeBuffer();
        }

    }

    private int readResults(byte[] b, int bPos, int bAvail) {
        if(this.buffer != null) {
            int len = Math.min(this.available(), bAvail);
            System.arraycopy(this.buffer, this.readPos, b, bPos, len);
            this.readPos += len;
            if(this.readPos >= this.pos) {
                this.buffer = null;
            }
            return len;
        }
        else {
            return this.eof ? -1 : 0;
        }
    }

    private void reset() {
        this.buffer = null;
        this.pos = 0;
        this.readPos = 0;
        this.modulus = 0;
        this.eof = false;
    }

    private byte[] decode(String pArray) throws Exception {
        return this.decode(getBytesUtf8(pArray));
    }

    private byte[] decode(byte[] pArray) {
        this.reset();
        if(pArray != null && pArray.length != 0) {
            this.decode(pArray, 0, pArray.length);
            this.decode(pArray, 0, -1);
            byte[] result = new byte[this.pos];
            this.readResults(result, 0, result.length);
            return result;
        } else {
            return pArray;
        }
    }

    private boolean containsAlphabetOrPad(byte[] arrayOctet) {
        if(arrayOctet == null) {
            return false;
        }
        else {
            for (byte element : arrayOctet) {
                if (61 == element || this.isInAlphabet(element)) {
                    return true;
                }
            }
            return false;
        }
    }

    private static byte[] getBytesUtf8(String string) throws Exception {
        return getBytesUnchecked(string, "UTF-8");
    }

    private static byte[] getBytesUnchecked(String string, String charsetName) throws Exception {
        return string.getBytes(charsetName);
    }

    private static String newString(byte[] bytes, String charsetName) throws Exception {
        return new String(bytes, charsetName);
    }

    private static String newStringUtf8(byte[] bytes) throws Exception {
        return newString(bytes, "UTF-8");
    }
}

Output would be as like if your user id and message id is correct:

Snippet=Hello bro how are you?Some italic mode text
Return-Path == xxx@gmail.com
From == xxx@gmail.com
Reply-To == "Reply To" <some_reply_address@gmails.com>
MIME-Version == 1.0
Date == Mon, 21 Nov 2016 00:31:53 -0500
Subject == Test email on: 21/11/2016 06:31:44
To == "To Address" <xxx@xxx.com>
Content-Type == multipart/mixed; boundary="5258f110dfc605186344f1668864cea5"
Message-Id == <CAD-od7dd=JedEjLxQPLLTMwJ93ZSpWdwZHsWD_eL-Jr1M=iWWA@mail.gmail.com>
Key=<<attachments>> == [
	{fileName=My-pdf.pdf, mimeBodyPart=javax.mail.internet.MimeBodyPart@490ab905, type=attachment, fileType=application/pdf}, 
	{fileName=My-image.png, mimeBodyPart=javax.mail.internet.MimeBodyPart@56ac3a89, type=attachment, fileType=image/png}
]
Key=<<html>> == <b>Hello bro how are you?</b><i style='color:blue;'>Some italic mode text</i>
Key=<<text>> ==