Skip to content
Spiderwiz

Spiderwiz

Let the wizard weave your web

Menu
  • About
  • Vision
  • Download
  • Tutorial
  • Javadoc
  • Blog
  • Contact

Lesson 16: Writing a Mail Plugin

We saw in Lesson 13 that a Spiderwiz-based application can be configured to automatically send notifications, alerts and exception reports by email. Currently Spiderwiz supports only SMTP mail, but other messaging systems can be added by writing a custom Mail plugin. We will see an example here.

We are going to write a WhatsApp messaging plugin. Actually it will be a dual system plugin. If the address to send to is of the form “whatsapp:<phone number>” then a WhatsApp message is sent, otherwise SMTP mail is used to send an email.

Mail plugins need to implement the ZMail interface. However since we want to revert to the standard SMTP mail when the addressee is not a WhatsApp account we will extend ZSMTPMail that is by itself an implementation of ZMail.

Our implementation uses the Twilio SDK. To use it, we need to include the following dependency:

<dependency>
    <groupId>com.twilio.sdk</groupId>
    <artifactId>twilio</artifactId>
    <version>7.54.2</version>
    <classifier>jar-with-dependencies</classifier>
</dependency>

With this in place, let’s see WhatsAppMail:

package org.spiderwiz.tutorial.lesson16;

import com.twilio.Twilio;
import com.twilio.rest.api.v2010.account.Message;
import com.twilio.type.PhoneNumber;
import java.io.UnsupportedEncodingException;
import java.util.Map;
import javax.mail.MessagingException;
import org.spiderwiz.zutils.ZHtml;
import org.spiderwiz.zutils.ZSMTPMail;

/**
 * A class that extends ZSMTPMail to implement a dual mail system. If the addressee is a WhatsApp phone number then the message is
 * sent via WhatsApp, otherwise the 'super' methods are called to process SMTP mail.
 * otherwise 
 */
public class WhatsAppMail extends ZSMTPMail {
    private final static String WHATSAPP_PREFIX = "whatsapp:";
    
    private String sid;
    private String auth;
    private String fromNumber;

    /**
     * Configure WhatsApp with a Twilio Account SID, Auth Token and the sender phone number,
     * then call the super method to configure SMTP mail.
     * @param configParams the configuration map.
     */
    @Override
    public synchronized void configure(Map<String, String> configParams) {
        sid = configParams.get("sid");
        auth = configParams.get("auth");
        fromNumber = configParams.get("from");
        if (fromNumber != null)
            fromNumber = WHATSAPP_PREFIX + fromNumber;
        super.configure(configParams);
    }
    
    @Override
    public void send(String from, String to, String cc, String subject, String body, boolean html, boolean highPriority)
        throws MessagingException, UnsupportedEncodingException
    {
        // Try first WhatsApp
        boolean toWhatsApp;
        boolean ccWhatsApp;
        if ((toWhatsApp = to != null && to.toLowerCase().startsWith(WHATSAPP_PREFIX)) |
            (ccWhatsApp = cc != null && cc.toLowerCase().startsWith(WHATSAPP_PREFIX))
        ) {
            Twilio.init(sid, auth);
            String text = "*" + subject + "*" + (html ? ZHtml.toPlainText(body) : "n" + body);
            if (toWhatsApp) {
                Message.creator(new PhoneNumber(to), new PhoneNumber(fromNumber), text).create();
                to = null;
            }
            if (ccWhatsApp) {
                Message.creator(new PhoneNumber(cc), new PhoneNumber(fromNumber), text).create();
                cc = null;
            }
        }
        
        // Call super for SMTP mail
        super.send(from, to, cc, subject, body, html, highPriority);
    }
}

There are just two methods that we need to implement, or override in our case. The first is configure() (line 29). The method receives a parameter map that maps keys to values, which is parsed from the mail system property of the application’s configuration file. To send a WhatsApp message we need three parameters:

  • sid        Twilio Account SID
  • auth      Auth Token
  • from      The WhatsApp sender’s phone number

We save the parameters for later use and call super.configure() to let the base class extract SMTP parameters.

The other method that we override is send() (line 40). This is also simple. We check if either to or cc are WhatsApp addresses and if so we send a WhatsApp message to any or both of them using the appropriate Twilio methods. Since the mail message might be formatted as HTML code that is not supported by WhatsApp, we convert it first to plain text using the static ZHtml.toPlainText() method that is part of the Spiderwiz framework. The converted text is preceded by a line that consists of the subject text enclosed by asterisks (*) to make it look bold on WhatsApp. When this is done we call super.send() to send the message to email addresses via SMTP.

To test the plugin with a chat application, rebuild it with the plugin in the CLASSPATH and configure it to something like this:

[application name]Chat 1
[log folder]/tests/Chat1/Logs
[backup folder]/tests/Chat1/Backup
[history file]/tests/Chat1/history.dat
[producer-1]websocket=localhost:90/MyHub
[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
[from address]Alerts<alert@whitehouse.gov>
[to email]Administrator<hell@whitehouse.gov>
[to exception email]Bug Reports<bugs@whitehouse.gov>
[cc exception email]whatsapp:+12024561111

The configuration of the mail system property includes the class parameter that refers to the fully qualified class name of the plugin. Other parameters define both WhatsApp and SMTP attributes as explained above.

Run the chat application, log in and then type something that should cause an exception, for instance:

!history 1od

A message with the description of the exception will be sent to the email address configured by to exception email and a (plain text) copy will be sent to the WhatsApp account configured by cc exception email.

The next lesson is the last in the “how to extend Spiderwiz” trilogy. We will talk about writing an Import Handler plugin.

Post navigation

Lesson 15: Writing a Communication Plugin
Lesson 17: Writing an Import Handler Plugin

Table of Contents

  • Lesson 1: Hello World
  • Lesson 2: Communication – Producers and Consumers
  • Lesson 3: Going World Wide with a WebSocket Hub
  • Lesson 4: Fine Grained Object Routing
  • Lesson 5: Persistent Data Objects and the Data Object Tree
  • Lesson 6: Walking Through the Data Object Tree
  • Lesson 7: Query Objects
  • Lesson 8: Streaming Queries and Data Object Archiving
  • Lesson 9: Manual Data Object Reset
  • Lesson 10: Asynchronous Event Handling
  • Lesson 11: Import/Export – Interfacing with Legacy Frameworks
  • Lesson 12: Don’t Miss a Bit – Lossless Data Objects
  • Lesson 13: Everything that Makes Maintenance Life Easier
  • Lesson 14: Monitor, Manage, Maintain and Control Your Applications with SpiderAdmin
  • Lesson 15: Writing a Communication Plugin
  • Lesson 16: Writing a Mail Plugin
  • Lesson 17: Writing an Import Handler Plugin
  • Lesson 18: Customizing SpiderAdmin
  • Where do We Go from Here?

Spiderwiz 2025 . Powered by WordPress