{"id":1010,"date":"2020-08-13T20:27:04","date_gmt":"2020-08-13T20:27:04","guid":{"rendered":"http:\/\/spiderwiz.org\/project\/?page_id=1010"},"modified":"2025-04-09T06:15:59","modified_gmt":"2025-04-09T06:15:59","slug":"lesson-16","status":"publish","type":"page","link":"https:\/\/spiderwiz.org\/project\/tutorial\/lesson-16\/","title":{"rendered":"Lesson 16: Writing a Mail Plugin"},"content":{"rendered":"\n<p class=\"wp-block-paragraph\">We saw in <a href=\"http:\/\/spiderwiz.org\/project\/tutorial\/lesson-13\/\">Lesson 13<\/a> that a Spiderwiz-based application can\nbe configured to automatically send notifications, alerts and exception reports\nby email. Currently Spiderwiz supports only SMTP mail, but other messaging\nsystems can be added by writing a custom Mail plugin. We will see an example\nhere.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">We are going to write a WhatsApp messaging plugin. Actually\nit will be a dual system plugin. If the address to send to is of the form\n\u201cwhatsapp:&lt;<em>phone number<\/em>&gt;\u201d then\na WhatsApp message is sent, otherwise SMTP mail is used to send an email.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Mail plugins need to implement the <a href=\"http:\/\/spiderwiz.org\/apidocs\/org\/spiderwiz\/zutils\/ZMail.html\">ZMail<\/a> interface. However since we want to revert\nto the standard SMTP mail when the addressee is not a WhatsApp account we will\nextend <a href=\"http:\/\/spiderwiz.org\/apidocs\/org\/spiderwiz\/zutils\/ZSMTPMail.html\">ZSMTPMail<\/a> that is by itself an implementation of <code>ZMail<\/code>.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Our implementation uses the <a href=\"https:\/\/www.twilio.com\/blog\/send-whatsapp-messages-java-applications-twilio-api\">Twilio SDK<\/a>. To use it, we need to include the\nfollowing dependency:<\/p>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre>&lt;dependency&gt;\n    &lt;groupId&gt;com.twilio.sdk&lt;\/groupId&gt;\n    &lt;artifactId&gt;twilio&lt;\/artifactId&gt;\n    &lt;version&gt;7.54.2&lt;\/version&gt;\n    &lt;classifier&gt;jar-with-dependencies&lt;\/classifier&gt;\n&lt;\/dependency&gt;<\/pre><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">With this in place, let\u2019s see <code>WhatsAppMail<\/code>:<\/p>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre>package org.spiderwiz.tutorial.lesson16;\n\nimport com.twilio.Twilio;\nimport com.twilio.rest.api.v2010.account.Message;\nimport com.twilio.type.PhoneNumber;\nimport java.io.UnsupportedEncodingException;\nimport java.util.Map;\nimport javax.mail.MessagingException;\nimport org.spiderwiz.zutils.ZHtml;\nimport org.spiderwiz.zutils.ZSMTPMail;\n\n\/**\n * A class that extends ZSMTPMail to implement a dual mail system. If the addressee is a WhatsApp phone number then the message is\n * sent via WhatsApp, otherwise the 'super' methods are called to process SMTP mail.\n * otherwise \n *\/\npublic class WhatsAppMail extends ZSMTPMail {\n    private final static String WHATSAPP_PREFIX = &quot;whatsapp:&quot;;\n    \n    private String sid;\n    private String auth;\n    private String fromNumber;\n\n    \/**\n     * Configure WhatsApp with a Twilio Account SID, Auth Token and the sender phone number,\n     * then call the super method to configure SMTP mail.\n     * @param configParams the configuration map.\n     *\/\n    @Override\n    public synchronized void configure(Map&lt;String, String&gt; configParams) {\n        sid = configParams.get(&quot;sid&quot;);\n        auth = configParams.get(&quot;auth&quot;);\n        fromNumber = configParams.get(&quot;from&quot;);\n        if (fromNumber != null)\n            fromNumber = WHATSAPP_PREFIX + fromNumber;\n        super.configure(configParams);\n    }\n    \n    @Override\n    public void send(String from, String to, String cc, String subject, String body, boolean html, boolean highPriority)\n        throws MessagingException, UnsupportedEncodingException\n    {\n        \/\/ Try first WhatsApp\n        boolean toWhatsApp;\n        boolean ccWhatsApp;\n        if ((toWhatsApp = to != null &amp;&amp; to.toLowerCase().startsWith(WHATSAPP_PREFIX)) |\n            (ccWhatsApp = cc != null &amp;&amp; cc.toLowerCase().startsWith(WHATSAPP_PREFIX))\n        ) {\n            Twilio.init(sid, auth);\n            String text = &quot;*&quot; + subject + &quot;*&quot; + (html ? ZHtml.toPlainText(body) : &quot;n&quot; + body);\n            if (toWhatsApp) {\n                Message.creator(new PhoneNumber(to), new PhoneNumber(fromNumber), text).create();\n                to = null;\n            }\n            if (ccWhatsApp) {\n                Message.creator(new PhoneNumber(cc), new PhoneNumber(fromNumber), text).create();\n                cc = null;\n            }\n        }\n        \n        \/\/ Call super for SMTP mail\n        super.send(from, to, cc, subject, body, html, highPriority);\n    }\n}<\/pre><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">There are just two methods that we need to implement, or\noverride in our case. The first is <a href=\"http:\/\/spiderwiz.org\/apidocs\/org\/spiderwiz\/zutils\/ZMail.html#configure(java.util.Map)\">configure()<\/a> (line 29). The method receives a\nparameter map that maps keys to values, which is parsed from the <code>mail system<\/code> property of the <a href=\"http:\/\/spiderwiz.org\/apidocs\/org\/spiderwiz\/core\/doc-files\/config.html#mailsystem\">application\u2019s configuration file<\/a>. To send a\nWhatsApp message we need three parameters:<\/p>\n\n\n\n<ul class=\"nobullet wp-block-list\"><li><code>sid<\/code>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0Twilio Account SID<\/li><li><code>auth<\/code>\u00a0\u00a0\u00a0\u00a0\u00a0 Auth Token<\/li><li><code>from<\/code>\u00a0\u00a0\u00a0\u00a0\u00a0 The WhatsApp sender\u2019s phone number<\/li><\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">We save the parameters for later use and call <code>super.configure()<\/code> to let the base class\nextract SMTP parameters.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The other method that we override is <a href=\"http:\/\/spiderwiz.org\/apidocs\/org\/spiderwiz\/zutils\/ZMail.html#send(java.lang.String,java.lang.String,java.lang.String,java.lang.String,java.lang.String,boolean,boolean)\">send()<\/a> (line 40). This is also simple. We check\nif either <code>to<\/code> or <code>cc<\/code> are WhatsApp addresses and if so we send a WhatsApp message to\nany or both of them using the appropriate Twilio methods. Since the mail\nmessage might be formatted as HTML code that is not supported by WhatsApp, we\nconvert it first to plain text using the static <a href=\"http:\/\/spiderwiz.org\/apidocs\/org\/spiderwiz\/zutils\/ZHtml.html#toPlainText(java.lang.String)\">ZHtml.toPlainText()<\/a> method that is part of the\nSpiderwiz framework. The converted text is preceded by a line that consists of\nthe <code>subject<\/code> text enclosed by\nasterisks (*) to make it look <strong>bold<\/strong>\non WhatsApp. When this is done we call <code>super.send()<\/code>\nto send the message to email addresses via SMTP.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">To test the plugin with a chat application, rebuild it with\nthe plugin in the CLASSPATH and configure it to something like this:<\/p>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre>[application name]Chat 1\n[log folder]\/tests\/Chat1\/Logs\n[backup folder]\/tests\/Chat1\/Backup\n[history file]\/tests\/Chat1\/history.dat\n[producer-1]websocket=localhost:90\/MyHub\n[mail system]class=org.spiderwiz.tutorial.lesson16.WhatsAppMail;sid=ACXXXXXXXXXXXX;auth=your_auth_token;from=+19177568000;server=smtp.gov;user=donaldt@whitehouse.gov;pwd=dumptrump;port=465;ssl=true\n[from address]Alerts&lt;alert@whitehouse.gov&gt;\n[to email]Administrator&lt;hell@whitehouse.gov&gt;\n[to exception email]Bug Reports&lt;bugs@whitehouse.gov&gt;\n[cc exception email]whatsapp:+12024561111<\/pre><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">The configuration of the <em>mail\nsystem<\/em> property includes the <code>class<\/code>\nparameter that refers to the fully qualified class name of the plugin. Other\nparameters define both WhatsApp and SMTP attributes as explained above.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Run the chat application, log in and then type something\nthat should cause an exception, for instance:<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><code>!history 1od<\/code><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">A message with the description of the exception will be sent\nto the email address configured by <em>to\nexception email<\/em> and a (plain text) copy will be sent to the WhatsApp\naccount configured by <code>cc exception email<\/code>.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The <a href=\"http:\/\/spiderwiz.org\/project\/tutorial\/lesson-17\/\">next lesson<\/a> is the last in the \u201chow to extend\nSpiderwiz\u201d trilogy. We will talk about writing an Import Handler plugin.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Learn how to extend Spiderwiz by writing and using a mail plugin. We will exercise sending messages through WhatsApp.<\/p>\n","protected":false},"author":1,"featured_media":0,"parent":145,"menu_order":16,"comment_status":"closed","ping_status":"closed","template":"tutorial-child.php","meta":{"footnotes":""},"class_list":["post-1010","page","type-page","status-publish","hentry"],"_links":{"self":[{"href":"https:\/\/spiderwiz.org\/project\/wp-json\/wp\/v2\/pages\/1010","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/spiderwiz.org\/project\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/spiderwiz.org\/project\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/spiderwiz.org\/project\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/spiderwiz.org\/project\/wp-json\/wp\/v2\/comments?post=1010"}],"version-history":[{"count":11,"href":"https:\/\/spiderwiz.org\/project\/wp-json\/wp\/v2\/pages\/1010\/revisions"}],"predecessor-version":[{"id":1428,"href":"https:\/\/spiderwiz.org\/project\/wp-json\/wp\/v2\/pages\/1010\/revisions\/1428"}],"up":[{"embeddable":true,"href":"https:\/\/spiderwiz.org\/project\/wp-json\/wp\/v2\/pages\/145"}],"wp:attachment":[{"href":"https:\/\/spiderwiz.org\/project\/wp-json\/wp\/v2\/media?parent=1010"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}