Friday, November 25, 2016

Java: Reading Email & Attachments From Different Email Server Using Javamail API

Download required jar for java mail from here.

Code snippet


package com.pritom.src;

import com.sun.mail.imap.IMAPFolder;
import com.sun.mail.imap.SortTerm;

import javax.mail.*;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeBodyPart;
import javax.mail.search.*;
import java.io.File;
import java.util.*;

/**
 * @author PRITOM
 * @date 2016-11-25
 */
public class ReadEmailFromServer {
    public static void main(String[] args) {
        gmail();
        //bleep();
        //yahoo();;
        //office();
    }

    private static void office() {
        String PROTOCOL = "imaps", HOST = "outlook.office365.com", USER = "xxxxx@outlook.com",
                PASSWORD = "xxxxx", ENCRYPTION_TYPE = "tls", PORT = "993";
        readEmail(PROTOCOL, HOST, USER, PASSWORD, ENCRYPTION_TYPE, PORT);
    }

    private static void yahoo() {
        String PROTOCOL = "imaps", HOST = "mail.yahoo.com", USER = "xxxxx@yahoo.com",
                PASSWORD = "xxxxx", ENCRYPTION_TYPE = "tls", PORT = "993";
        readEmail(PROTOCOL, HOST, USER, PASSWORD, ENCRYPTION_TYPE, PORT);
    }

    private static void bleep() {
        String PROTOCOL = "imaps", HOST = "bleep.xxxxx.com", USER = "pritom@xxxxx.com",
                PASSWORD = "xxxxx", ENCRYPTION_TYPE = "tls", PORT = "993";
        readEmail(PROTOCOL, HOST, USER, PASSWORD, ENCRYPTION_TYPE, PORT);
    }

    private static void gmail() {
        String PROTOCOL = "imaps", HOST = "imap.gmail.com", USER = "xxxxx@gmail.com",
                PASSWORD = "xxxxx", ENCRYPTION_TYPE = "tls", PORT = "993";
        readEmail(PROTOCOL, HOST, USER, PASSWORD, ENCRYPTION_TYPE, PORT);
    }

    private static void readEmail(String PROTOCOL, String HOST, String USER, String PASSWORD, String ENCRYPTION_TYPE, String PORT) {
        Properties props = new Properties();
        props.setProperty("mail.store.protocol", PROTOCOL);
        if(ENCRYPTION_TYPE.length() > 0 && !ENCRYPTION_TYPE.equalsIgnoreCase("none")) {
            if(PROTOCOL.equalsIgnoreCase("imap")) {
                props.setProperty("mail.imap.socketFactory.class", "javax.net.ssl.SSLSocketFactory");
                props.setProperty("mail.imap.socketFactory.fallback", "false");
                props.setProperty("mail.imap.ssl.enable", "true");
                props.setProperty("mail.imap.socketFactory.port", PORT.length() > 0 ? PORT : "993");
                if(ENCRYPTION_TYPE.equalsIgnoreCase("tls")) {
                    props.setProperty("mail.imap.starttls.enable", "true");
                }
            }
            else if(PROTOCOL.equalsIgnoreCase("pop3")) {
                props.setProperty("mail.pop3.socketFactory.class", "javax.net.ssl.SSLSocketFactory");
                props.setProperty("mail.pop3.socketFactory.fallback", "false");
                props.setProperty("mail.pop3.ssl.enable", "true");
                props.setProperty("mail.pop3.socketFactory.port", PORT.length() > 0 ? PORT : "995");
                if(ENCRYPTION_TYPE.equalsIgnoreCase("tls")) {
                    props.setProperty("mail.pop3.starttls.enable", "true");
                }
            }
        }
        try {
            Session session = Session.getInstance(props, null);
            Store store = session.getStore();
            store.connect(HOST, USER, PASSWORD);
            printAllFolders(store);
            IMAPFolder inbox = (IMAPFolder) store.getFolder("INBOX");
            inbox.open(Folder.READ_ONLY);

            SortTerm[] sortTerms = new SortTerm[1];
            sortTerms[0] = SortTerm.ARRIVAL;
            Message[] messages = inbox.getSortedMessages(sortTerms, getSearchCriteria());

            int maxReadNumber = 1;
            int total = messages.length > maxReadNumber ? maxReadNumber : messages.length;
            println("\nTotal_Email = " + messages.length);
            boolean ascending = false;
            for (int index = 0; index < total; index++) {
                int message_index = ascending ? index : messages.length - index - 1;
                Message message = messages[message_index];
                String subject = message.getSubject();
                println("-------------------------------------------------------------------------------------------");
                println("-------------------------------------------------------------------------------------------");
                println("------------------" + (index + 1) + "/" + messages.length + "----------------------" + subject);
                println("-------------------------------------------------------------------------------------------");
                println("-------------------------------------------------------------------------------------------");
                printAllHeaders(message);
                if (message.getContent() instanceof String) {
                    println("\tContent---------------Type=" + message.getContentType());
                    String body = message.getContent().toString();
                    body = body.length() > 100 ? body.substring(0, 100) + "..." : body;
                    println("\t\t" + toSingleLine(body));
                }
                else {
                    Map output = processMultipart((Multipart) message.getContent());
                    Object[] keys = output.keySet().toArray();
                    for (int i = 0; i < keys.length; i++) {
                        println("\t" + keys[i].toString().toUpperCase() + "-------------------------------------------");
                        if (keys[i].toString() == "attachments") {
                            List attachments = (List) output.get("attachments");
                            for (int j = 0; j < attachments.size(); j++) {
                                Map attachment = (Map) attachments.get(j);
                                /* You can save attachments to your local machine by uncomment line below */
                                //String toFile = saveFileFromEmailAttachment(attachment);
                                //println("File_Saved_To=" + toFile);
                                println("\t\tFile_Name=" + attachment.get("fileName"));
                            }
                        }
                        else {
                            String body = output.get(keys[i].toString()).toString().trim();
                            body = body.length() > 100 ? body.substring(0, 100) + "..." : body;
                            println("\t\t[[[" + toSingleLine(body) + "]]]");
                        }
                    }
                }
                if (total == index + 1) {
                    println("-------------------------------------------------------------------------------------------");
                    println("-------------------------------------------------------------------------------------------");
                    println("-------------------------------------------------------------------------------------------");
                }
            }
            inbox.close(false);
            store.close();
        }
        catch (Exception ex) {
            ex.printStackTrace();
        }
    }

    private static void printAllFolders(Store store) throws Exception {
        println("Folders:::");
        Folder[] folders = store.getDefaultFolder().list();
        for (Folder folder : folders) {
            println("\t" + folder.getFullName());
            for (Folder subFolder : folder.list()) {
                println("\t\t" + subFolder.getFullName());
            }
        }
    }

    private static void printAllHeaders(Message message) throws Exception {
        Enumeration enumeration = message.getAllHeaders();
        while (enumeration.hasMoreElements()) {
            Header header = (Header) enumeration.nextElement();
            boolean show = !header.getName().startsWith("X-") && !header.getName().equals("Received");
            show = show && !header.getName().startsWith("Authentication-") && !header.getName().startsWith("DKIM-");
            if (show) {
                println("\t" + header.getName() + "===" + toSingleLine(header.getValue()));
            }
        }
    }

    private static SearchTerm getSearchCriteria() throws Exception {
        if (true) {
            //return null;
            //return new FlagTerm(new Flags(Flags.Flag.SEEN), false);
            //return new MessageIDTerm("CAD-oc7fMFqioVurtMPnGm63mWAA51wELBaLhtm38zvthTv0+DQ@mail.gmail.com");
        }
        FlagTerm unread = new FlagTerm(new Flags(Flags.Flag.SEEN), false);
        FromTerm fromTerm = new FromTerm(new InternetAddress("pritomkucse@gmail.com"));

        Calendar cal = Calendar.getInstance();
        /* Set date to 1 day back from now */
        cal.roll(Calendar.DATE, false);
        ReceivedDateTerm latest = new ReceivedDateTerm(DateTerm.GT, cal.getTime());
        SearchTerm andTerm = new AndTerm(unread, latest);

        SearchTerm notFromTerm = new NotTerm(new FromTerm(new InternetAddress("black_listed_domain.com")));

        SubjectTerm subjectTerm = new SubjectTerm("Notable");
        OrTerm orTerm = new OrTerm(fromTerm, new OrTerm(andTerm, subjectTerm));
        AndTerm andTerm1 = new AndTerm(orTerm, notFromTerm);
        /**
         * (FROM_pritomkucse@gmail.com OR (NOT_REED AND YESTERDAY) OR SUBJECT_CONTAINS_Notable) AND NOT_FROM_*@black_listed_domain.com
         */

        /* Custom search term, actually download email from server then check (slow) */
        SearchTerm searchTerm = new SearchTerm() {
            @Override
            public boolean match(Message message) {
                try {
                    if (message.getSubject().contains("forwarding")) {
                        return true;
                    }
                }
                catch (MessagingException ex) {
                    ex.printStackTrace();
                }
                return false;
            }
        };

        return andTerm1;
    }

    private static String saveFileFromEmailAttachment(Map attachment) {
        try {
            File dir = createAndGetDirectory();
            String fileName = attachment.get("fileName").toString();
            File toFile = new File(dir, fileName);
            MimeBodyPart mimeBodyPart = (MimeBodyPart) attachment.get("mimeBodyPart");
            mimeBodyPart.saveFile(toFile);
            return toFile.getAbsolutePath();
        }
        catch (Exception e) {
            e.printStackTrace();
            return e.getMessage();
        }
    }

    private static File createAndGetDirectory() {
        File file = new File("attachments");
        if (!file.exists()) {
            file.mkdir();
        }
        return file;
    }

    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) {
            try {
                Map map = new HashMap();
                map.put("type", "attachment");
                map.put("fileName", bodyPart.getFileName());
                String fileType = bodyPart.getContentType();
                map.put("fileType", fileType.contains(":") ? fileType.substring(0, fileType.indexOf(";")) : fileType);
                map.put("mimeBodyPart", bodyPart);
                return map;
            }
            catch (Exception ex) {
                println("Error_Content=" + bodyPart.getContentType());
                ex.printStackTrace();
            }
        }
        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 println(Object o) {
        System.out.println(o);
    }
}

How to add custom validation to an AngularJS form field


<!DOCTYPE html>
<html>
<head>
<title>How to add custom validation to an AngularJS form field</title>
<style type="text/css">
    div.log {
        border: 2px solid gray;
        color: black;
        padding: 10px;
        font-size: 20px;
        font-family: monospace;
    }
    div.log div {
        padding: 10px;
    }
</style>

<script src="http://code.angularjs.org/1.2.12/angular.js"></script>
<script src="http://code.jquery.com/jquery-2.1.1.min.js"></script>

<script type="text/javascript">
    var app = angular.module("myApp", []);

    app.controller("MyCustomValidationController", function($scope, $http) {
        $scope.items = [];
        $scope.items.push({"name": "Pritom", "type": "A"});
        $scope.items.push({"name": "Kumar", "type": "B"});

        var log = $(".log");
        $scope.log = function(e) {
            log.prepend("<div>" + e + "</div>");
        }

        $scope.error = function(e) {
            log.prepend("<div style='color:red;'>" + e + "</div>");
        }
    })

    app.directive("myCustomValidation", function() {
        return {
            restrict: "A",
            require: "ngModel",         
            link: function(scope, elem, attrs, ctrl) {
                ctrl.$parsers.unshift(function(v) {
                    scope.$evalAsync(function() {
                        scope.log("Parsers=" + v)
                    })
                    if(v.length > 10) {
                        ctrl.$setValidity('myCustomValidation', false)
                    }
                    else {
                        ctrl.$setValidity('myCustomValidation', true)
                    }
                    return v
                })
                ctrl.$formatters.unshift(function(v) {
                    scope.$evalAsync(function() {
                        scope.log("Formatters=" + v)
                    })
                    return v
                })
                elem.on('keyup', function (evt) {
                    if(ctrl.$error.maxlength) {
                        scope.$evalAsync(function() {
                            scope.error("Maxlength")
                        })
                    }
                    if(ctrl.$error.required) {
                        scope.$evalAsync(function() {
                            scope.error("Required")
                        })
                    }
                    if(ctrl.$error.myCustomValidation) {
                        scope.$evalAsync(function() {
                            scope.error("MyCustomValidation")
                        })
                    }
                })
            }
        }
    })
</script>
</head>

<body>
 <div data-ng-app="myApp" data-ng-controller="MyCustomValidationController">
     <div>
         <div ng-form="myForm" data-ng-repeat="item in items">
             <div style="border:1px solid blue;padding:10px;">
                <input type="text" name="name" ng-model="item.name" ng-maxlength="10" 
                       my-custom-validation required style="width:50%;"/>
                <select ng-model="item.type" my-custom-validation required style="width:48%;" name="type">
                    <option value="">None</option>
                    <option value="A">A</option>
                    <option value="B">B</option>
                    <option value="C">C</option>
                </select>
             </div>
         </div>
         <div class="log"></div>
     </div>
 </div>
</body>
</html>


Thursday, November 24, 2016

Send email using Php & Outlook / Office 365 using Oauth connection

To get oauth access token & other information used in this code snippet visit:
http://pritomkumar.blogspot.com/2016/11/write-php-app-to-get-outlook-office-365.html

Code snippet to send email using php via Office 365 account & oauth


<?php
session_start();
init();

if(isset($_POST["send"])) {
    $attachments = array();
    for($i = 0; $i < 6; $i++) {
        if(strlen(trim($_FILES["files"]["name"][$i])) > 0) {
            $content = base64_encode(file_get_contents($_FILES["files"]["tmp_name"][$i]));
            $attachment = array(
                "@odata.type" => "#Microsoft.OutlookServices.FileAttachment",
                "Name" => $_FILES["files"]["name"][$i],
                "ContentBytes" => $content
            );
            array_push($attachments, $attachment);
        }
    }

    $to = array();
    $toFromForm = explode(";", $_POST["to"]);
    foreach ($toFromForm as $eachTo) {
        if(strlen(trim($eachTo)) > 0) {
            $thisTo = array(
                "EmailAddress" => array(
                    "Address" => trim($eachTo)
                )
            );
            array_push($to, $thisTo);
        }
    }
    if (count($to) == 0) {
        die("Need email address to send email");
    }

    $request = array(
        "Message" => array(
            "Subject" =>$_POST["subject"],
            "ToRecipients" => $to,
            "Attachments" => $attachments,
            "Body" => array(
                "ContentType" => "HTML",
                "Content" => utf8_encode($_POST["message"])
            )
        )
    );

    $request = json_encode($request);
    $headers = array(
        "User-Agent: php-tutorial/1.0",
        "Authorization: Bearer ".$_SESSION["access_token"],
        "Accept: application/json",
        "Content-Type: application/json",
        "Content-Length: ". strlen($request)
    );

    $response = runCurl($_SESSION["api_url"], $request, $headers);
    echo "<pre>"; print_r($response); echo "</pre>";
    /* if $response["code"] == 202 then mail sent successfully */
}
else {
?>
<form method="post" enctype="multipart/form-data" accept-charset="ISO-8859-1">
<table style="width: 1000px;">
    <tr>
        <td style="width: 150px;">To</td>
        <td style="width: 850px;"><input type="text" name="to" required value="" style="width: 100%;"/></td>
    </tr>
    <tr>
        <td>Subject</td>
        <td><input type="text" name="subject" required value="Some sample subject on <?php echo date("d/m/Y H:i:s"); ?>" style="width: 100%;"/></td>
    </tr>
    <tr>
        <td>Files</td>
        <td>
            <input type="file" name="files[]"/>
            <input type="file" name="files[]"/>
            <input type="file" name="files[]"/>
            <input type="file" name="files[]"/>
            <input type="file" name="files[]"/>
            <input type="file" name="files[]"/>
        </td>
    </tr>
    <tr>
        <td style="vertical-align: top;">Message</td>
        <td><textarea name="message" required style="width: 100%; height: 600px;"></textarea></td>
    </tr>
    <tr>
        <td></td>
        <td><input type="submit" name="send" value="Send"/></td>
    </tr>
</table>
</form>
<?php
}

function init() {
    $_SESSION["scopes"] = array("offline_access", "openid", "https://outlook.office.com/mail.send");

    $_SESSION["api_url"] = "https://outlook.office.com/api/v2.0/me/sendmail";

    $_SESSION["access_token"] = "eyJ0eXAiOiJKV1QidfsdfsdfsdfSUzI1NiIsIng1dCI6IlJyUXF1OXJ5ZEJWUldtY29jdVhVYjIwSEdSTSIsImtpZCI6IlJyUXF1OXJ5ZEJWUldtY29jdVhVYjIwSEdSTSJ9.eyJhdWQiOiJodHRwczovL291dGxvb2sub2ZmaWNlLmNvbSIsImlzcyI6Imh0dHBzOi8vc3RzLndpbmRvd3MubmV0LzdkOTAzZjM5LTkxZGYtNGVmMS04ZDY0LTcxNDMwOTlhMTVmMC8iLCJpYXQiOjE0Nzk5NjE2NjAsIm5iZiI6MTQ3OTk2MTY2MCwiZXhwIjoxNDc5OTY1NTYwLCJhY3IiOiIxIiwiYW1yIjpbInB3ZCJdLCJhcHBpZCI6ImRhOGE1NGQ4LTg2YjUtNDE5Ni05ODFlLWUzMWVmYTNmM2Q1OSIsImFwcGlkYWNyIjoiMSIsImZhbWlseV9uYW1lIjoiQmlsbCIsImdpdmVuX25hbWUiOiJBdXRvIiwiaXBhZGRyIjoiMTAzLjQuMTQ2LjE4NiIsIm5hbWUiOiJBdXRvIEJpbGwiLCJvaWQiOiI5NGM1NTZlMy1jYmM1LTQxMTItYWJhZi0yMmUxZDVkNWU2ZjQiLCJwbGF0ZiI6IjMiLCJwdWlkIjoiMTAwMzAwMDA5QzcyRTlGRiIsInNjcCI6Ik1haWwuUmVhZCBNYWlsLlNlbmQiLCJzdWIiOiJ4SF9JNzl0bFRwbGI0WG41RktKSHZ6VTBkU2pJOUNBaDVCaElWTnljMTBNIiwidGlkIjoiN2Q5MDNmMzktOTFkZi00ZWYxLThkNjQtNzE0MzA5OWExNWYwIiwidW5pcXVlX25hbWUiOiJhdXRvYmlsbEB3ZWJhbGl2ZS5jb20uYXUiLCJ1cG4iOiJhdXRvYmlsbEB3ZWJhbGl2ZS5jb20uYXUiLCJ2ZXIiOiIxLjAifQ.a9RnBzxlChE8-_kfTcYuQy2lbpVsZOKIpn-fmSjePi5oiX4aPL-SZ6xL9rwdjL4SWeOyiDLHmVs3jhEbHkEIZhD4aqzbvqTovQOUluyHOAHVjQJyRc6AV6g-WP4jmbCDVOKFvvq9llZ13Srihvua1wFCM5z-nDZsIVY0LzTeew8-ZTM5trVEG9QtyR_UmlgLgwbIOl9PWz0MvFcCLbFiZQ8-1zGje8oL_fbm8vFtRdP_bNS6OzyatupFvAQRM4RhFQYHhuxKCVzI35JoEWfhHtUZAReTYwRfBULEJuT_CIkC0G7DyWJR1IRVnaYSWagvj93tOZtIaU-OMSsovmYEtg";
}

function runCurl($url, $post = null, $headers = null) {
    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, $url);
    curl_setopt($ch, CURLOPT_POST, $post == null ? 0 : 1);
    if($post != null) {
        curl_setopt($ch, CURLOPT_POSTFIELDS, $post);
    }
    curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_ANY);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
    if($headers != null) {
        curl_setopt($ch, CURLOPT_HEADER, true);
        curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
    }
    $response = curl_exec($ch);
    $http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
    curl_close($ch);
    if($http_code >= 400) {
        echo "Error executing request to Office365 api with error code=$http_code<br/><br/>\n\n";
        echo "<pre>"; print_r($response); echo "</pre>";
        die();
    }
    return array("code" => $http_code, "response" => $response);
}
?>

Php read email & attachments from google using oauth

You can get access token & other details to perform this action:
http://pritomkumar.blogspot.com/2016/11/using-oauth-20-for-google-client-side.html

Code snippet to read email & attachments from google using oauth

<?php
session_start();
init();
if(isset($_GET["email_id"])) {
    email_details();
}
else if(isset($_GET["email_attachment"])) {
    email_attachment();
}
else {
    list_email();
}

function init() {
    $_SESSION["google_user_id"] = "11822454346345607576118";
    $_SESSION["access_token"] = "ya29.CjCgA8bf_BCrsdfsdfsdfsdf5orH3cvbMMzQY0RX8NUrbgpNhm9oXHyAAZ0WF3Jid4WwQ";

    /* Permissions to read email */
    $_SESSION["scope"] = "https://www.googleapis.com/auth/userinfo.profile"; /* User profile */
    $_SESSION["scope"] .= " https://www.googleapis.com/auth/gmail.readonly"; /* Read mail */
}

function email_attachment() {
    $id = $_GET["email_attachment"];
    $name = $_GET["name"];
    if (!file_exists("attachments")) {
        mkdir("attachments");
    }

    $apiUrl = "https://www.googleapis.com/gmail/v1/users/".$_SESSION["google_user_id"];
    $apiUrl .= "/messages/$id/attachments/".$id;
    $apiUrl .= "?access_token=".$_SESSION["access_token"];
    $remoteFile = decode_content(json_decode(make_request($apiUrl))->data);
    $file = "attachments/".md5(time()).$name;
    file_put_contents($file, $remoteFile);
    header("Location: $file");
    exit;
}

function email_details() {
    $id = $_GET["email_id"];
    $raw = "";// "format=raw&";
    $fields = "";// "fields=raw&";
    $apiUrl = "https://www.googleapis.com/gmail/v1/users/";
    $apiUrl .= $_SESSION["google_user_id"]."/messages/$id?$raw$fields";
    $apiUrl .= "access_token=".$_SESSION["access_token"];
    //echo $apiUrl; die();
    $result = json_decode(make_request($apiUrl));
    //file_put_contents("raw-email.txt", $result->raw); die();
    //echo "<pre>"; print_r($result); echo "</pre>"; die();

    $message = parse_email($result->payload->parts);
    $link = ""; $html = "";
    foreach($message as $msg) {
        if($msg["type"] == "html") {
            $html = $msg["body"];
        }
        else if($msg["type"] == "text") {
            //you can do anything with text part of email
        }
        else {
            $link .= "<a href='?email_attachment=".$msg["body"]."&name=".$msg["name"]."' target='_blank'>".$msg["name"]."</a><br/>";
        }
    }
    echo "<h3><i>Email Attachments:</i></h3>".$link."<h3><i>Email Body:</i></h3>".trim($html);
}

function parse_email($email) {
    $result = array();
    for($i = 0; $i < count($email); $i++) {
        $part = $email[$i];
        $mime = $part->mimeType;
        $name = $part->filename;
        if(strlen($name) > 0) {
            $file = array();
            $file["type"] = $mime;
            $file["name"] = $name;
            $file["body"] = $part->body->attachmentId;
            array_push($result, $file);
        }
        else if($mime === "text/plain") {
            $file = array();
            $file["type"] = "text";
            $file["name"] = "email_body_plain.html";
            $file["body"] = decode_content($part->body->data);
            array_push($result, $file);
        }
        else if($mime === "text/html") {
            $file = array();
            $file["type"] = "html";
            $file["name"] = "email_body_html.html";
            $file["body"] = decode_content($part->body->data);
            array_push($result, $file);
        }
        else if(substr($mime, 0, 9) === "multipart") {
            foreach(parse_email($part->parts) as $file) {
                array_push($result, $file);
            }
        }
    }
    return $result;
}

function decode_content($content) {
    return base64_decode(str_replace("-", "+", str_replace("_", "/", $content)));
}

function list_email() {
    //gmail api ref page: https://developers.google.com/gmail/api/v1/reference/
    //https://developers.google.com/gmail/api/v1/reference/users/messages/list
    //Searching filtering gmail over oauth2 api using php
    //https://developers.google.com/gmail/api/guides/filtering
    //https://support.google.com/mail/answer/7190?hl=en

    $search = "from:pritom@xxx.com OR from:pritomkucse@gmail.com"; //Search by from address
    $search = "subject:Fwd:"; //Words in the subject line
    $search = "label:sent OR label:starred"; //With certain labels
    $search = "has:attachment"; //Any email with attachments
    $search = "is:important"; //Important mails only
    $search = "is:read"; //For mails those are read already
    $search = "is:unread"; //For mails those are not read yet
    $search = "cc:pritomkucse@gmail.com"; //Emails has specific cc, bcc not allowed
    $search = "after:2016/11/19 AND label:inbox"; //Emails reached inbox after specific date
    $search = "before:2016/04/19 AND label:inbox"; //Emails reached inbox before specific date
    $search = "has:nouserlabels"; //Emails with no labels
    $search = "deliveredto:pritom@xxx.com"; //Emails delivered to some address
    $search = "size:10000"; //Email larger than bytes
    $search = "larger:15M"; //Emails larger than megabytes
    $search = "smaller:1M"; //Emails smaller than megabytes
    $search = "newer_than:1d"; //Emails newer than 1 day (d/m/y)
    $search = "older_than:20d"; //Emails older than 1 day (d/m/y)
    $search = "category:updates"; //Emails in specific category
    $search = "rfc822msgid:2021140448.450273.1479617087520.JavaMail.zimbra@bitmascot.com"; //Specific message by Message-ID
    $search = "!from:@gmail.com"; //Search by not from domain
    $search = "!from:pritomkucse@google.com"; //Search by not from address
    $search = ""; //No filtering

    $maxResults = 10;
    $apiUrl = "https://www.googleapis.com/gmail/v1/users/".$_SESSION["google_user_id"]."/messages?";
    $apiUrl .= "access_token=".$_SESSION["access_token"];
    $apiUrl .= "&maxResults=".$maxResults;
    if(strlen($search) > 0) {
        $apiUrl .= "&q=" . urlencode($search);
    }
    if(isset($_GET["next_page"]) && strlen($_GET["next_page"]) > 0) {
        $apiUrl .= "&pageToken=". $_GET["next_page"];
    }
    $result = json_decode(make_request($apiUrl));
    //echo "<pre>";print_r($result);echo "</pre>";die();

    if(isset($result->messages)) {
        foreach($result->messages as $m) {
            $link = "<a target='_blank' href='?email_id=".$m->id."'>View Message [[".$m->id . "]]</a><br/>";
            echo $link;
        }
    }
    else {
        echo "<pre>"; print_r($result); echo "</pre>"; die();
    }
    if(isset($result->nextPageToken)) {
        echo "<a href='?email=true&next_page=".$result->nextPageToken."'>Next_Page</a>";
    }
}

function make_request($url, $post = null, $headers = null, $returnArray = false) {
    $curl = curl_init();
    curl_setopt($curl, CURLOPT_URL, $url);
    curl_setopt($curl, CURLOPT_POST, $post == null ? 0 : 1);
    if($post != null) {
        curl_setopt($curl, CURLOPT_POSTFIELDS, $post);
    }
    curl_setopt($curl, CURLOPT_HTTPAUTH, CURLAUTH_ANY);
    curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
    curl_setopt($curl, CURLOPT_SSLVERSION, 1);
    if($headers != null) {
        curl_setopt($curl, CURLOPT_HEADER, true);
        curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);
    }
    $response = curl_exec($curl);
    $http_code = curl_getinfo($curl, CURLINFO_HTTP_CODE);
    $header_size = curl_getinfo($curl, CURLINFO_HEADER_SIZE);
    curl_close($curl);
    if($http_code >= 400) {
        echo "Error executing request to Office365 api with error code=$http_code<br/><br/>\n\n";
        echo "<pre>"; print_r($response); echo "</pre>";
        die();
    }
    if($returnArray) {
        return array(
            "response" => $response,
            "header_size" => $header_size
        );
    }
    return $response;
}
?>

Tuesday, November 22, 2016

Write a PHP app to get/read Outlook Office 365 mail using oauth connection

1. Go to https://apps.dev.microsoft.com/#/appList
2. Click on "Add an app"
3. Put a name on "New Application Registration" form such "My App"
4. And click "Create application" button
5. It will redirect to you your application page:
https://apps.dev.microsoft.com/#/application/da8a54d8-86b5-4196-981e-XXXXXXXXXX
6. Find the button "Generate New Password" and click
7. Copy the password: "pYJAiGeYTXXXXXXXvzhfp"
8. Find "Platforms" button and click "Add platform" and select "Web"
9. Enter your application url in the field "Redirect URIs" 
http://localhost/tappi/office.php (Your uri would be different)
10. And click on "Save" button
11. Done from this end.

Api reference: https://dev.outlook.com/restapi/reference




Now follow the php code snippet (full example to get user profile, read email & send email):


<?php
session_start();
init();

if(token()) {
    echo "<a href='".$_SESSION["redirect_uri"]."''>Home</a>";
    echo " || <a href='".$_SESSION["redirect_uri"]."?refresh_token=true'>Refresh token</a>";
    echo " || <a href='".$_SESSION["redirect_uri"]."?profile=true'>Profile</a>";
    echo " || <a href='".$_SESSION["redirect_uri"]."?list_email=true'>List Email</a>";
    echo " || <a href='".$_SESSION["redirect_uri"]."?logout=true'>Logout</a><br/><br/>\n\n";
}

if(isset($_GET["logout"])) {
    flush_token();
    echo "Logged out<br/>";
    echo "<a href='".$_SESSION["redirect_uri"]."'>Start new session</a>";
    die();
}
else if(isset($_GET["profile"])) {
    view_profile();
}
else if(isset($_GET["refresh_token"])) {
    refresh_token();
}
else if(isset($_GET["list_email"])) {
    list_email();
}
else if(isset($_GET["view_email"])) {
    view_email();
}
else if(isset($_GET["view_attachments"])) {
    view_attachments();
}
else if(token()) {
    echo "<pre>"; print_r(token()); echo "</pre>";
}
elseif (isset($_GET["code"])) {
    echo "<pre>";print_r($_GET);echo "</pre>";
    $token_request_data = array (
        "grant_type" => "authorization_code",
        "code" => $_GET["code"],
        "redirect_uri" => $_SESSION["redirect_uri"],
        "scope" => implode(" ", $_SESSION["scopes"]),
        "client_id" => $_SESSION["client_id"],
        "client_secret" => $_SESSION["client_secret"]
    );
    $body = http_build_query($token_request_data);
    $response = runCurl($_SESSION["authority"].$_SESSION["token_url"], $body);
    $response = json_decode($response);

    store_token($response);
    file_put_contents("office_active_user_id.txt", get_user_id());
    file_put_contents("office_access_token.txt", $response->access_token);
    header("Location: " . $_SESSION["redirect_uri"]);
}
else {
    $accessUrl = $_SESSION["authority"].$_SESSION["auth_url"];
    echo "<a href='$accessUrl'>Login with Office 365</a>";
}

function view_email() {
    $mailID = $_GET["view_email"];
    $userID = get_user_id();
    $headers = array(
        "User-Agent: php-tutorial/1.0",
        "Authorization: Bearer ".token()->access_token,
        "Accept: application/json",
        "client-request-id: ".makeGuid(),
        "return-client-request-id: true",
        "X-AnchorMailbox: ". get_user_email()
    );
    $outlookApiUrl = $_SESSION["api_url"] . "/Users('$userID')/Messages('$mailID')";
    $response = runCurl($outlookApiUrl, null, $headers);
    $response = explode("\n", trim($response));
    $response = $response[count($response) - 1];
    $response = json_decode($response, true);
    echo "<pre>"; print_r($response); echo "</pre>";
}

function view_attachments() {
    $mailID = $_GET["view_attachments"];
    $folder = "Office-" . md5($mailID);
    if(!file_exists($folder)) {
        mkdir($folder);
    }
    $userID = get_user_id();
    $headers = array(
        "User-Agent: php-tutorial/1.0",
        "Authorization: Bearer ".token()->access_token,
        "Accept: application/json",
        "client-request-id: ".makeGuid(),
        "return-client-request-id: true",
        "X-AnchorMailbox: ". get_user_email()
    );
    $outlookApiUrl = $_SESSION["api_url"] . "/Users('$userID')/Messages('$mailID')/Attachments";
    $response = runCurl($outlookApiUrl, null, $headers);
    $response = explode("\n", trim($response));
    $response = $response[count($response) - 1];
    $response = json_decode($response, true);
    $file_links = "";
    foreach ($response["value"] as $attachment) {
        $to_file = $folder . "/" . md5($attachment["ContentId"]) . "-" . $attachment["Name"];
        file_put_contents($to_file, base64_decode($attachment["ContentBytes"]));
        if($file_links != "") {
            $file_links = $file_links . " ||| ";
        }
        $file_links .= "<a href='$to_file' target='_blank'>" . $attachment["Name"] . "</a>";
    }
    echo $file_links . "<br/><br/>";
    echo "<pre>"; print_r($response); echo "</pre>";
}

function list_email() {
    $headers = array(
        "User-Agent: php-tutorial/1.0",
        "Authorization: Bearer ".token()->access_token,
        "Accept: application/json",
        "client-request-id: ".makeGuid(),
        "return-client-request-id: true",
        "X-AnchorMailbox: ". get_user_email()
    );
    $top = 2;
    $skip = isset($_GET["skip"]) ? intval($_GET["skip"]) : 0;
    $search = array (
        // Only return selected fields
        "\$select" => "Subject,ReceivedDateTime,Sender,From,ToRecipients,HasAttachments,BodyPreview",
        // Sort by ReceivedDateTime, newest first
        "\$orderby" => "ReceivedDateTime DESC",
        // Return at most n results
        "\$top" => $top, "\$skip" => $skip
    );
    $outlookApiUrl = $_SESSION["api_url"] . "/Me/MailFolders/Inbox/Messages?" . http_build_query($search);
    $response = runCurl($outlookApiUrl, null, $headers);
    $response = explode("\n", trim($response));
    $response = $response[count($response) - 1];
    $response = json_decode($response, true);
    //echo "<pre>"; print_r($response); echo "</pre>";
    if(isset($response["value"]) && count($response["value"]) > 0) {
        echo "<style type='text/css'>td{border: 2px solid #cccccc;padding: 30px;text-align: center;vertical-align: top;}</style>";
        echo "<table style='width: 100%;'><tr><th>From</th><th>Subject</th><th>Preview</th></tr>";
        foreach ($response["value"] as $mail) {
            $BodyPreview = str_replace("\n", "<br/>", $mail["BodyPreview"]);
            echo "<tr>";
            echo "<td>".$mail["From"]["EmailAddress"]["Address"].
                "<br/><a target='_blank' href='?view_email=".$mail["Id"]."'>View Email</a>";
            if($mail["HasAttachments"] == 1) {
                echo "<br/><a target='_blank' href='?view_attachments=".$mail["Id"]."'>View Attachments</a>";
            }
            echo "</td><td>".$mail["Subject"]."</td>";
            echo "<td>".$BodyPreview."</td>";
            echo "</tr>";
        }
        echo "</table>";
    }
    else {
        echo "<div><h3><i>No email found</i></h3></div>";
    }
    $prevLink = "";
    if($skip > 0) {
        $prev = $skip - $top;
        $prevLink = "<a href='?list_email=true&skip=".$prev."'>Previous Page</a>";
    }
    if(isset($response["@odata.nextLink"])) {
        if($prevLink != "") {
            $prevLink .= " ||| ";
        }
        echo "<br/>".$prevLink."<a href='?list_email=true&skip=".($skip + $top)."'>Next Page</a>";
    }
    else {
        echo "<br/>" . $prevLink;
    }
}

function refresh_token() {
    $token_request_data = array (
        "grant_type" => "refresh_token",
        "refresh_token" => token()->refresh_token,
        "redirect_uri" => $_SESSION["redirect_uri"],
        "scope" => implode(" ", $_SESSION["scopes"]),
        "client_id" => $_SESSION["client_id"],
        "client_secret" => $_SESSION["client_secret"]
    );
    $body = http_build_query($token_request_data);
    $response = runCurl($_SESSION["authority"].$_SESSION["token_url"], $body);
    $response = json_decode($response);
    store_token($response);
    file_put_contents("office_access_token.txt", $response->access_token);
    header("Location: " . $_SESSION["redirect_uri"]);
}

function get_user_id() {
    if(isset($_SESSION["user_id"]) && strlen($_SESSION["user_id"]) > 0) {
        return $_SESSION["user_id"];
    }
    view_profile(true);
    $response = json_decode(file_get_contents("office_user_data.txt"));
    $_SESSION["user_id"] = $response->Id;
    return $response->Id;
}

function get_user_email() {
    if(isset($_SESSION["user_email"]) && strlen($_SESSION["user_email"]) > 0) {
        return $_SESSION["user_email"];
    }
    view_profile(true);
    $response = json_decode(file_get_contents("office_user_data.txt"));
    $_SESSION["user_email"] = $response->EmailAddress;
    return $response->EmailAddress;
}

function view_profile($skipPrint = false) {
    $headers = array(
        "User-Agent: php-tutorial/1.0",
        "Authorization: Bearer ".token()->access_token,
        "Accept: application/json",
        "client-request-id: ".makeGuid(),
        "return-client-request-id: true"
    );
    $outlookApiUrl = $_SESSION["api_url"] . "/Me";
    $response = runCurl($outlookApiUrl, null, $headers);
    $response = explode("\n", trim($response));
    $response = $response[count($response) - 1];
    file_put_contents("office_user_data.txt", $response);
    $response = json_decode($response);
    $_SESSION["user_id"] = $response->Id;
    $_SESSION["mail_id"] = $response->MailboxGuid;
    $_SESSION["user_email"] = $response->EmailAddress;
    if(!$skipPrint) {
        echo "<pre>"; print_r($response); echo "</pre>";
    }
}

function makeGuid(){
    if (function_exists('com_create_guid')) {
        error_log("Using 'com_create_guid'.");
        return strtolower(trim(com_create_guid(), '{}'));
    }
    else {
        $charid = strtolower(md5(uniqid(rand(), true)));
        $hyphen = chr(45);
        $uuid = substr($charid, 0, 8).$hyphen
            .substr($charid, 8, 4).$hyphen
            .substr($charid, 12, 4).$hyphen
            .substr($charid, 16, 4).$hyphen
            .substr($charid, 20, 12);
        return $uuid;
    }
}

function flush_token() {
    file_put_contents("office_auth_config.txt", "");
    $_SESSION["user_id"] = "";
    $_SESSION["mail_id"] = "";
}

function store_token($o) {
    file_put_contents("office_auth_config.txt", json_encode($o));
}

function token() {
    $text = file_exists("office_auth_config.txt") ? file_get_contents("office_auth_config.txt") : null;
    if($text != null && strlen($text) > 0) {
        return json_decode($text);
    }
    return null;
}

function init() {
    $_SESSION["client_id"] = "da8a54d8-86b5-xxxx-xxxx-e31efa3f3d59";
    $_SESSION["client_secret"] = "pYJAxxxxxxxxxxxxxxxX3vzhfp";
    $_SESSION["redirect_uri"] = "http://localhost/tappi/office.php";
    $_SESSION["authority"] = "https://login.microsoftonline.com";
    $_SESSION["scopes"] = array("offline_access", "openid");
    /* If you need to read email, then need to add following scope */
    if(true) {
        array_push($_SESSION["scopes"], "https://outlook.office.com/mail.read");
    }
    /* If you need to send email, then need to add following scope */
    if(true) {
        array_push($_SESSION["scopes"], "https://outlook.office.com/mail.send");
    }

    $_SESSION["auth_url"] = "/common/oauth2/v2.0/authorize";
    $_SESSION["auth_url"] .= "?client_id=".$_SESSION["client_id"];
    $_SESSION["auth_url"] .= "&redirect_uri=".$_SESSION["redirect_uri"];
    $_SESSION["auth_url"] .= "&response_type=code&scope=".implode(" ", $_SESSION["scopes"]);

    $_SESSION["token_url"] = "/common/oauth2/v2.0/token";

    $_SESSION["api_url"] = "https://outlook.office.com/api/v2.0";
}

function runCurl($url, $post = null, $headers = null) {
    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, $url);
    curl_setopt($ch, CURLOPT_POST, $post == null ? 0 : 1);
    if($post != null) {
        curl_setopt($ch, CURLOPT_POSTFIELDS, $post);
    }
    curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_ANY);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
    if($headers != null) {
        curl_setopt($ch, CURLOPT_HEADER, true);
        curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
    }
    $response = curl_exec($ch);
    $http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
    curl_close($ch);
    if($http_code >= 400) {
        echo "Error executing request to Office365 api with error code=$http_code<br/><br/>\n\n";
        echo "<pre>"; print_r($response); echo "</pre>";
        die();
    }
    return $response;
}
?>