Commit 46928120 authored by Sonia Zorba's avatar Sonia Zorba
Browse files

Improved email generation using the library PHPMailer

parent 97c4886b
Loading
Loading
Loading
Loading

.gitignore

deleted100644 → 0
+0 −6
Original line number Diff line number Diff line
vendor
composer.lock
nbproject
logs
config.php
test
+160 −0
Original line number Diff line number Diff line
<?php

namespace RAP;

/**
 * This class is used to build an e-mail message body both in HTML and in its
 * equivalent plaintext.
 */
class MailBodyBuilder {

    private $htmlBody;
    private $textBody;
    private $openedHTMLTags;
    private $editable;

    function __construct() {
        $this->htmlBody = "";
        $this->textBody = "";
        $this->openedHTMLTags = [];
        $this->editable = true;
    }

    private function checkEditable() {
        if (!$this->editable) {
            throw new \Exception("You cannot edit the body after it has been generated");
        }
    }

    public function addText($text) {
        $this->checkEditable();
        $this->htmlBody .= $text;
        $this->textBody .= $text;
        return $this;
    }

    public function addLineBreak() {
        $this->checkEditable();
        $this->htmlBody .= "<br>\n";
        $this->textBody .= "\n";
        return $this;
    }

    public function addHr() {
        $this->checkEditable();
        $this->htmlBody .= "<hr/>\n";
        $this->textBody .= "\n---------------------\n";
        return $this;
    }

    public function addLinkWithDescription($url, $text) {
        $this->checkEditable();
        $this->htmlBody .= '<a href="' . $url . '" target="blank_">' . $text . "</a>\n";
        $this->textBody .= $text . " ( " . $url . " ) ";
        return $this;
    }

    public function addLink($url) {
        $this->checkEditable();
        $this->htmlBody .= '<a href="' . $url . '" target="blank_">' . $url . "</a>\n";
        $this->textBody .= $url . " ";
        return $this;
    }

    public function addEmailAddress($email, $description) {
        $this->checkEditable();
        $this->htmlBody .= '<a href="mailto:' . $email . '">' . $description . '</a>';
        $this->textBody .= $description . " (" . $email . ")";
        return $this;
    }

    private function openHTMLTag($tag, $equivalentPlainText) {
        $this->checkEditable();
        if (in_array($tag, $this->openedHTMLTags)) {
            throw new \Exception("You are already inside a " . $tag . " tag!");
        }
        $this->openedHTMLTags[] = $tag;
        $this->htmlBody .= "<" . $tag . ">";
        $this->textBody .= $equivalentPlainText;
        return $this;
    }

    private function closeHTMLTag($tag, $equivalentPlainText) {
        $this->checkEditable();
        if ($this->openedHTMLTags[count($this->openedHTMLTags) - 1] !== $tag) {
            throw new \Exception("You are not inside a " . $tag . " tag!");
        }
        array_pop($this->openedHTMLTags);
        $this->htmlBody .= "</" . $tag . ">";
        $this->textBody .= $equivalentPlainText;
        return $this;
    }

    public function startBold() {
        return $this->openHTMLTag("strong", "*");
    }

    public function endBold() {
        return $this->closeHTMLTag("strong", "*");
    }

    public function startParagraph() {
        return $this->openHTMLTag("p", "");
    }

    public function endParagraph() {
        return $this->closeHTMLTag("p", "\n");
    }

    public function startList() {
        return $this->openHTMLTag("ul", "\n");
    }

    public function startListItem() {
        return $this->openHTMLTag("li", " * ");
    }

    public function endListItem() {
        return $this->closeHTMLTag("li", "\n");
    }

    public function endList() {
        return $this->closeHTMLTag("ul", "\n");
    }

    private function checkEnd() {
        if (count($this->openedHTMLTags) > 0) {
            $unclosedTags = "";
            foreach ($this->openedHTMLTags as $tag) {
                $unclosedTags .= $tag . " ";
            }
            throw new \Exception("You must close all tags before generating email body! Unclosed tags: " . $unclosedTags);
        }
    }

    private function setCompatibleLineBreaks($value) {
        return str_replace("\n", "\n\r", $value);
    }

    private function finalizeBodyIfNecessary() {
        if ($this->editable) {
            $this->checkEnd();

            $this->htmlBody = $this->setCompatibleLineBreaks($this->htmlBody);
            $this->textBody = $this->setCompatibleLineBreaks($this->textBody);

            $this->editable = false;
        }
    }

    public function getTextPlainBody() {
        $this->finalizeBodyIfNecessary();
        return $this->textBody;
    }

    public function getHTMLBody() {
        $this->finalizeBodyIfNecessary();
        return $this->htmlBody;
    }

}
+75 −30
Original line number Diff line number Diff line
@@ -24,6 +24,8 @@

namespace RAP;

use \PHPMailer\PHPMailer\PHPMailer;

/**
 * Manage mail sending.
 * Currently used only for join email messages.
@@ -32,10 +34,20 @@ class MailSender {

    private $serverName;
    private $basePath;
    private $mbb;

    public function __construct($serverName, $basePath) {
        $this->serverName = $serverName;
        $this->basePath = $basePath;
        $this->mbb = new MailBodyBuilder();
    }

    private function addDescriptionItem($key, $value) {
        $this->mbb->startBold()
                ->addText($key)
                ->endBold()
                ->addText(": " . $value)
                ->addLineBreak();
    }

    /**
@@ -47,53 +59,86 @@ class MailSender {
     */
    public function sendJoinEmail(User $recipientUser, User $applicantUser, $token) {

        $subject = "IA2 RAP: Join request";

        $header = "From: noreply@" . $this->serverName . "\r\n";
        $header .= "Content-Type: text/html; charset=UTF-8";
        global $auditLog;

        $confirmJoinURL = $this->basePath . '/confirm-join?token=' . $token;

        $body = "Dear IA2 user,<br/><br/>";
        $body .= "the following user requested to join your accounts on the "
                . "<a href=\"https://sso.ia2.inaf.it/rap-ia2/\" target=\"blank_\">RAP facility</a>:<br/><br/>";
        $this->mbb->startParagraph()
                ->addText("Dear IA2 user,")
                ->addLineBreak()
                ->addText("the following user requested to join your accounts on the ")
                ->addLinkWithDescription("https://sso.ia2.inaf.it/rap-ia2/", "RAP facility")
                ->addText(":")
                ->endParagraph();

        foreach ($applicantUser->identities as $identity) {

            $body .= "<b>Type</b>: " . $identity->type . "<br/>";

            $this->addDescriptionItem("Type", $identity->type);
            if ($identity->name !== null) {
                $body .= "<b>Name</b>: " . $identity->name . "<br/>";
                $this->addDescriptionItem("Name", $identity->name);
            }

            if ($identity->surname !== null) {
                $body .= "<b>Surname</b>: " . $identity->surname . "<br/>";
                $this->addDescriptionItem("Surname", $identity->surname);
            }

            $body .= "<b>E-mail</b>: " . $identity->email . "<br/>";

            $this->addDescriptionItem("E-mail", $identity->email);
            if ($identity->eppn !== null) {
                $body .= "<b>Eppn</b>: " . $identity->eppn . "<br/>";
                $this->addDescriptionItem("Eppn", $identity->eppn);
            }

            if ($identity->institution !== null) {
                $body .= "<b>Institution</b>: " . $identity->institution . "<br/>";
                $this->addDescriptionItem("Institution", $identity->institution);
            }

            $body .= "<br/>";
            $this->mbb->addLineBreak();
        }

        $body .= "<br/>If you and this user are <b>the same person</b> click on the following link for joining your accounts:<br/>";
        $body .= "<a href=\"$confirmJoinURL\" target=\"blank_\">$confirmJoinURL</a>";
        $body .= "<br/><br/>Otherwise you can ignore this email.<br/>";

        $body .= '<p><b>Please don\'t use this functionality for sharing resources between your coworkers</b>, use <a href="https://sso.ia2.inaf.it/grouper">Grouper</a> for that.</p>';
        $body .= '<br/>';

        $body .= "<b>*** This is an automatically generated email, please do not reply to this message ***</b><br/>";
        $body .= "If you need information please contact <a href=\"mailto:ia2@oats.inaf.it\">IA2 Staff</a>";

        mail($recipientUser->getPrimaryEmail(), $subject, $body, $header);
        $this->mbb->startParagraph()
                ->addText("If you and this user are ")
                ->startBold()
                ->addText("the same person")
                ->endBold()
                ->addText(" click on the following link for joining your accounts: ")
                ->addLink($confirmJoinURL)
                ->addLineBreak()
                ->addText("Otherwise you can ignore this email.")
                ->endParagraph()
                //
                ->startParagraph()
                ->startBold()
                ->addText("Please don't use this functionality for sharing resources between your coworkers")
                ->endBold()
                ->addText(", use ")
                ->addLinkWithDescription("https://sso.ia2.inaf.it/grouper", "Grouper")
                ->addText(" for that.")
                ->endParagraph()
                //
                ->addLineBreak()
                ->startBold()
                ->addText("*** This is an automatically generated email, please do not reply to this message ***")
                ->endBold()
                ->addLineBreak()
                ->addText("If you need information please contact ")
                ->addEmailAddress("ia2@oats.inaf.it", "IA2 Staff");

        $mail = new PHPMailer(true); // Passing `true` enables exceptions
        try {

            $toAddress = $recipientUser->getPrimaryEmail();

            $mail->isSMTP();
            $mail->Port = 25;
            $mail->setFrom("noreply@" . $this->serverName, 'IA2 SSO');
            $mail->addAddress($toAddress);
            $mail->CharSet = 'utf-8';
            $mail->Subject = "IA2 RAP: Join request";
            $mail->Body = $this->mbb->getHTMLBody();
            $mail->AltBody = $this->mbb->getTextPlainBody();

            $auditLog->info("JOIN email. Sending to " . $toAddress);
            $mail->send();
        } catch (\Exception $ex) {
            error_log($ex->getMessage());
            throw $ex;
        }
    }

}
+2 −1
Original line number Diff line number Diff line
@@ -3,6 +3,7 @@
        "mikecao/flight": "1.3.2",
        "google/apiclient": "2.1.3",
        "facebook/graph-sdk": "^5.5",
        "monolog/monolog": "^1.22"
        "monolog/monolog": "^1.22",
        "phpmailer/phpmailer": "^6.0"
    }
}