Inbound message API: Difference between revisions
(Updated key length and corrected some mistakes.) |
David Mudrak (talk | contribs) m (Text replacement - "<code php>" to "<syntaxhighlight lang="php">") |
||
(8 intermediate revisions by 5 users not shown) | |||
Line 1: | Line 1: | ||
{{Infobox Project | {{Infobox Project | ||
|name = | |name = Inbound Message API | ||
|state = | |state = Complete | ||
|tracker = MDL- | |tracker = MDL-46282 | ||
|discussion = https://moodle.org/mod/forum/discuss.php?d=269424 | |||
|assignee = Andrew Nicols | |assignee = Andrew Nicols | ||
}} | }} | ||
{{Moodle 2.8}} | {{Moodle 2.8}} | ||
== | == Summary == | ||
By encoding pieces of data within an e-mail address, it is possible to route a message within Moodle and to | |||
handle it accordingly. With the encoding of appropriate data within the e-mail address, it is also possible to perform | |||
By encoding pieces of data within an e-mail address, it is possible to route | |||
handle it accordingly. With the encoding of appropriate data within | |||
some level of sender verification, and to store additional data to enable further routing. | some level of sender verification, and to store additional data to enable further routing. | ||
To ensure that the solution remains practical, a single incoming e-mail account is used, making use | To ensure that the solution remains practical, a single incoming e-mail account is used, making use of the e-mail | ||
Subaddress extension defined in RFC 5233 (Sieve Email Filtering: Subaddress Extension). This RFC specifies that a '+' | Subaddress extension defined in RFC 5233 (Sieve Email Filtering: Subaddress Extension). This RFC specifies that a the '+' | ||
can be used to separate the mailbox from any additional subaddress data. For example, in the e-mail address | symbol can be used to separate the mailbox from any additional subaddress data. For example, in the e-mail address | ||
`bob+moodle@example.com, the e-mail would be delivered to `bob@example.com` but the recipient would be able to filter | `bob+moodle@example.com, the e-mail would be delivered to `bob@example.com` but the recipient would be able to filter | ||
mail based on the +moodle extension. | mail based on the +moodle extension. This extension is referred to as the subaddress. | ||
The maximum length of the localpart of an e-mail address (including subadress) as defined in RFC 5232, is 64 | |||
characters. The current maximum length of the subaddress component is 48 characters, with a further character used for | characters. The current maximum length of the subaddress component is 48 characters, with a further character used for | ||
the subaddress separator. This leaves space for 15 characters in the address component. | the subaddress separator. This leaves space for 15 characters in the address component. | ||
Line 29: | Line 27: | ||
The main benefits of this kind of handling are the addition of new ways of interacting with Moodle for certain content: | The main benefits of this kind of handling are the addition of new ways of interacting with Moodle for certain content: | ||
* | * the ability for users to reply to content received from Moodle; and | ||
* | * the ability to e-mail new content in to Moodle. | ||
This has other potential knock-on benefits for users who cannot use the Moodle mobile application, or to unusual | This has other potential knock-on benefits for users who cannot use the Moodle mobile application, or to unusual | ||
scenarios where Internet access may be unusually limited. | scenarios where Internet access may be unusually limited. It also allows users to respond in a natural, and familiar environment which mirrors that of other systems. | ||
== Components == | == Components == | ||
The | The Inbound Message Handling system is broken down into several main components: | ||
# Address Management | # Address Management | ||
Line 44: | Line 42: | ||
# Message retrieval system | # Message retrieval system | ||
In order to preserve user-verification, each | In order to preserve user-verification, each address used in the process must be unique to that user. Additionally, | ||
the message must identify how the message should be handled within Moodle. | the message must identify how the message should be handled within Moodle. | ||
A handler is only passed a message following successful verification of that message and may decide how it will handle | A handler is only passed a message following successful verification of that message and may decide how it will handle | ||
the message from that point on. | the message from that point on. | ||
Handlers may define certain characteristics of the message handling system including: | |||
# the extent of the verification which takes place; and | |||
# the default validity period. | |||
=== Address Manager === | === Address Manager === | ||
An address and routing manager exists to: | An address and routing manager exists to: | ||
# | # generate unique addresses; | ||
# | # process received messages, and extract the data stored within them; | ||
# | # validate addresses; and | ||
# | # verify sender authenticity. | ||
Both an encode, and a decode stage exist. | Both an encode, and a decode stage exist. | ||
Note: It is up to the developer to use the generated address in the correct fashion. Typically this will be as a 'reply-to' address when sending new messages. | |||
==== Creating an e-mail address (Encode stage) ==== | ==== Creating an e-mail address (Encode stage) ==== | ||
When creating a new e-mail address, the following information is required: | When creating a new e-mail address, the following information is required: | ||
# the system which will handle any e-mail received to the generated address; | # the '''handler''' - the system which will handle any e-mail received to the generated address; | ||
# a single | # the '''data value''' - a single integer data which the received message relates to; and | ||
# the id of the user that a message relates to. | # the '''user id''' - the id of the user that a message relates to. | ||
A '''data key''' is generated for the supplied data value. | |||
In the following example, an e-mail address is generated when sending a new forum post notification to a user. This | In the following example, an e-mail address is generated when sending a new forum post notification to a user. This | ||
address is used in the reply-to field when sending the message, thereby allowing a user to reply to a post by e-mail. | address is used in the reply-to field when sending the message, thereby allowing a user to reply to a post by e-mail. | ||
A new handler has been written for the forum | A new handler has been written for the forum <syntaxhighlight lang="php">\mod\forum\message\inbound\reply_handler</syntaxhighlight> which is aware of how it should handle any | ||
received information. | received information. | ||
The forum post notification will be sent to the user described by $recipient with a unique user id of $recipient->id. | The forum post notification will be sent to the user described by $recipient with a unique user id of <syntaxhighlight lang="php">$recipient->id</syntaxhighlight>. | ||
The forum post notification describes a new post described by $post and with a unique post id of $post->id. | The forum post notification describes a new post described by $post and with a unique post id of <syntaxhighlight lang="php">$post->id</syntaxhighlight>. | ||
< | <syntaxhighlight lang="php"> | ||
// Create a new instance of the address manager. | // Create a new instance of the address manager. | ||
$generator = new \core\ | $generator = new \core\message\inbound\address_manager(); | ||
// Specify the handler which will process any incoming messages for the generated address. | // Specify the handler which will process any incoming messages for the generated address. | ||
$generator->set_handler('\mod\forum\ | $generator->set_handler('\mod\forum\message\inbound\reply_hander'); | ||
// Specify the post that is being replied to. | // Specify the post that is being replied to. | ||
Line 87: | Line 93: | ||
// Generate an e-mail address to use for the reply-to, unique to this recipient. | // Generate an e-mail address to use for the reply-to, unique to this recipient. | ||
$generator->generate($recipient->id); | $replyaddress = $generator->generate($recipient->id); | ||
</ | |||
$eventdata = new stdClass(); | |||
$eventdata->component = 'mod_forum'; | |||
$eventdata->name = 'posts'; | |||
$eventdata->userfrom = $userfrom; | |||
$eventdata->userto = $userto; | |||
$eventdata->subject = $postsubject; | |||
$eventdata->fullmessage = $posttext; | |||
$eventdata->fullmessageformat = FORMAT_PLAIN; | |||
$eventdata->fullmessagehtml = $posthtml; | |||
$eventdata->notification = 1; | |||
$eventdata->replyto = $replyaddress; | |||
</syntaxhighlight> | |||
The e-mail address generated will be of the nature: | The e-mail address generated will be of the nature: | ||
Line 101: | Line 119: | ||
The following example address can be parsed to determine the sender, the handler, and the item of data to which the | The following example address can be parsed to determine the sender, the handler, and the item of data to which the | ||
message refers. | message refers. Note that this has been implemented as core functionality and developers are not expected to need to implement this section themselves. | ||
<pre> | <pre> | ||
incoming+AAAAFXrQKf8AA3QP92///wABUl2Ukn//uCbIXwoNLnXy94kV@example.com | incoming+AAAAFXrQKf8AA3QP92///wABUl2Ukn//uCbIXwoNLnXy94kV@example.com | ||
Line 112: | Line 130: | ||
// Create a new instance of the address manager. | // Create a new instance of the address manager. | ||
$parser = new \core\ | $parser = new \core\message\inbound\address_manager(); | ||
// First parse the envelope data. | // First parse the envelope data. | ||
Line 118: | Line 136: | ||
// We can check that the data validation passed. | // We can check that the data validation passed. | ||
if ($result !== \core\ | if ($result !== \core\message\inbound\address::VALIDATION_SUCCESS) { | ||
echo "Some part of the data could not be verified\n"; | echo "Some part of the data could not be verified\n"; | ||
} else { | } else { | ||
Line 124: | Line 142: | ||
$data = $result->get_data(); | $data = $result->get_data(); | ||
// Get the instance of the handler - this will be the \mod_forum\ | // Get the instance of the handler - this will be the \mod_forum\message\inbound\reply_hander used to define the message originally. | ||
$data->get_handler(); | $data->get_handler(); | ||
Line 139: | Line 157: | ||
Once a message has been processed by the address manager, it is passed to the handler specified in the address data. | Once a message has been processed by the address manager, it is passed to the handler specified in the address data. | ||
Each Handler belongs to a specific component, and comprises of a class extending \core\ | Each Handler belongs to a specific component, and comprises of a class extending \core\message\inbound\handler, which specifies a | ||
function to handle any received e-mail messages. | function to handle any received e-mail messages. | ||
Line 145: | Line 163: | ||
To create a new handler, you must: | To create a new handler, you must: | ||
# create a | # create a class extending the handler class; and | ||
# specify it's default values in that component's db/ | # specify it's default values in that component's db/messageinbound_handlers.php file. | ||
Each new handler must have a unique class name within Moodle and must be loadable using the Moodle class autoloader. | Each new handler must have a unique class name within Moodle and must be loadable using the Moodle class autoloader. | ||
Line 160: | Line 178: | ||
|- | |- | ||
! scope="row" | Namespace | ! scope="row" | Namespace | ||
| mod_forum\ | | mod_forum\message\inbound | ||
|- | |- | ||
! scope="row" | Class Name | ! scope="row" | Class Name | ||
| mod_forum\ | | mod_forum\message\inbound\reply_handler | ||
|} | |} | ||
In mod/forum/db/ | In mod/forum/db/messageinbound_handlers.php, define the available handlers. | ||
< | |||
<syntaxhighlight lang="php"> | |||
<?php | <?php | ||
Line 174: | Line 193: | ||
$handlers = array( | $handlers = array( | ||
array( | array( | ||
'classname' => '\mod_forum\ | 'classname' => '\mod_forum\message\inbound\reply_handler', | ||
'enabled' => false, | |||
'validateaddress' => true, | |||
), | ), | ||
); | ); | ||
</ | </syntaxhighlight> | ||
And define the handler itself in /mod/forum/classes/message/inbound/reply_handler.php: | |||
And define the handler itself in /mod/forum/classes/ | <syntaxhighlight lang="php"> | ||
< | |||
<?php | <?php | ||
namespace mod_forum\ | namespace mod_forum\message\inbound; | ||
defined('MOODLE_INTERNAL') || die(); | defined('MOODLE_INTERNAL') || die(); | ||
class reply_handler extends \core\ | class reply_handler extends \core\message\inbound\handler { | ||
// Place the content of the handler here. | // Place the content of the handler here. | ||
} | } | ||
</syntaxhighlight> | |||
A handler class must define three abstract functions: | |||
# get_name() - Typically a string returned by get_string() to display as a name in the admin interface; | |||
A handler class must define | |||
# get_description() - Typically a string returned by get_string() to display in the admin interface; and | # get_description() - Typically a string returned by get_string() to display in the admin interface; and | ||
# process_message() - The function called after successful validation of a message, which takes information including the recipient, sender, headers, body, and a list of attachments. | # process_message() - The function called after successful validation of a message, which takes information including the recipient, sender, headers, body, and a list of attachments. | ||
A new handler must also be defined within the component in lib/db/ | It may optionally define some additional functions: | ||
# allow_validateaddress_change() - To prevent an Moodle administrator from changing whether E-mail address validation is required. Typically this is used to '''force''' sender validation. | |||
# allow_enabled_change() - To prevent a Moodle administrator from enabling, or disabling the handler | |||
A new handler must also be defined within the component in lib/db/messageinbound_handlers.php. This array of handlers | |||
includes the default settings for the handler used at creation time. | includes the default settings for the handler used at creation time. | ||
==== Removing quoted text from email messages ==== | |||
If you want the quoted text to be removed from email messages you can call the method remove_quoted_text from inside your handler as below:- | |||
<syntaxhighlight lang="php"> | |||
list ($message, $format) = self::remove_quoted_text($messagedata); | |||
</syntaxhighlight> | |||
The method will make an educated guess and remove quoted text from the message and return the format and message contents. This method doesn't work perfectly at the moment and MDL-50058 is supposed to improve this. | |||
== Validation and Verification == | == Validation and Verification == | ||
The | The Inbound Message system performs a step of both validation, and verification. | ||
Note: E-mail is never a secure method of communication, and it is easy to `spoof` the `sender` field when sending an | Note: E-mail is never a secure method of communication, and it is easy to `spoof` the `sender` field when sending an | ||
e-mail very easily. As a result, administrators should be fully aware of the consequences when enabling any | e-mail very easily. As a result, administrators should be fully aware of the consequences when enabling any Inbound Message | ||
handler. | handler. | ||
Line 237: | Line 269: | ||
As an additional prevention method, the handler could define a further e-mail based verification check whereby on | As an additional prevention method, the handler could define a further e-mail based verification check whereby on | ||
reception of | reception of an inboune e-mail, the handler system would: | ||
# store the retrieved message (park it); | # store the retrieved message (park it); | ||
# send a new e-mail to the user described in $user containing a link or a further reply message; and | # send a new e-mail to the user described in $user containing a link or a further reply message; and | ||
Line 244: | Line 276: | ||
==== Spoofed e-mail address ==== | ==== Spoofed e-mail address ==== | ||
As mentioned above, it is incredibly easy to spoof the Sender field in an e-mail. If the full | As mentioned above, it is incredibly easy to spoof the Sender field in an e-mail. If the full address is captured | ||
by an attacker, then it would be possible to send e-mail as that user and the | by an attacker, then it would be possible to send e-mail as that user and the Inbound Message system would be unable to distinguish | ||
the message from a valid address. | the message from a valid address. | ||
Line 282: | Line 314: | ||
Although it would be possible to increase the length of an address, doing so would invalidate all previously used | Although it would be possible to increase the length of an address, doing so would invalidate all previously used | ||
addresses. | addresses. | ||
[[File:verp-prototype-screen-examples.png]] |
Latest revision as of 13:26, 14 July 2021
Inbound Message API | |
---|---|
Project state | Complete |
Tracker issue | MDL-46282 |
Discussion | https://moodle.org/mod/forum/discuss.php?d=269424 |
Assignee | Andrew Nicols |
Moodle 2.8
Summary
By encoding pieces of data within an e-mail address, it is possible to route a message within Moodle and to handle it accordingly. With the encoding of appropriate data within the e-mail address, it is also possible to perform some level of sender verification, and to store additional data to enable further routing.
To ensure that the solution remains practical, a single incoming e-mail account is used, making use of the e-mail Subaddress extension defined in RFC 5233 (Sieve Email Filtering: Subaddress Extension). This RFC specifies that a the '+' symbol can be used to separate the mailbox from any additional subaddress data. For example, in the e-mail address `bob+moodle@example.com, the e-mail would be delivered to `bob@example.com` but the recipient would be able to filter mail based on the +moodle extension. This extension is referred to as the subaddress.
The maximum length of the localpart of an e-mail address (including subadress) as defined in RFC 5232, is 64 characters. The current maximum length of the subaddress component is 48 characters, with a further character used for the subaddress separator. This leaves space for 15 characters in the address component.
Benefits
The main benefits of this kind of handling are the addition of new ways of interacting with Moodle for certain content:
- the ability for users to reply to content received from Moodle; and
- the ability to e-mail new content in to Moodle.
This has other potential knock-on benefits for users who cannot use the Moodle mobile application, or to unusual scenarios where Internet access may be unusually limited. It also allows users to respond in a natural, and familiar environment which mirrors that of other systems.
Components
The Inbound Message Handling system is broken down into several main components:
- Address Management
- Message Handling
- Handler Management
- Message retrieval system
In order to preserve user-verification, each address used in the process must be unique to that user. Additionally, the message must identify how the message should be handled within Moodle.
A handler is only passed a message following successful verification of that message and may decide how it will handle the message from that point on.
Handlers may define certain characteristics of the message handling system including:
- the extent of the verification which takes place; and
- the default validity period.
Address Manager
An address and routing manager exists to:
- generate unique addresses;
- process received messages, and extract the data stored within them;
- validate addresses; and
- verify sender authenticity.
Both an encode, and a decode stage exist.
Note: It is up to the developer to use the generated address in the correct fashion. Typically this will be as a 'reply-to' address when sending new messages.
Creating an e-mail address (Encode stage)
When creating a new e-mail address, the following information is required:
- the handler - the system which will handle any e-mail received to the generated address;
- the data value - a single integer data which the received message relates to; and
- the user id - the id of the user that a message relates to.
A data key is generated for the supplied data value.
In the following example, an e-mail address is generated when sending a new forum post notification to a user. This address is used in the reply-to field when sending the message, thereby allowing a user to reply to a post by e-mail.
A new handler has been written for the forum
\mod\forum\message\inbound\reply_handler
which is aware of how it should handle any
received information.
The forum post notification will be sent to the user described by $recipient with a unique user id of
$recipient->id
. The forum post notification describes a new post described by $post and with a unique post id of
$post->id
.
// Create a new instance of the address manager.
$generator = new \core\message\inbound\address_manager();
// Specify the handler which will process any incoming messages for the generated address.
$generator->set_handler('\mod\forum\message\inbound\reply_hander');
// Specify the post that is being replied to.
$generator->set_data($post->id);
// Generate an e-mail address to use for the reply-to, unique to this recipient.
$replyaddress = $generator->generate($recipient->id);
$eventdata = new stdClass();
$eventdata->component = 'mod_forum';
$eventdata->name = 'posts';
$eventdata->userfrom = $userfrom;
$eventdata->userto = $userto;
$eventdata->subject = $postsubject;
$eventdata->fullmessage = $posttext;
$eventdata->fullmessageformat = FORMAT_PLAIN;
$eventdata->fullmessagehtml = $posthtml;
$eventdata->notification = 1;
$eventdata->replyto = $replyaddress;
The e-mail address generated will be of the nature:
incoming+AAAAFXrQKf8AA3QP92///wABUl2Ukn//uCbIXwoNLnXy94kV@example.com
Parsing an e-mail address (Decode and validation stage)
When an e-mail is received, the 'To' address field is parsed to determine the way in which the e-mail should be processed.
The following example address can be parsed to determine the sender, the handler, and the item of data to which the message refers. Note that this has been implemented as core functionality and developers are not expected to need to implement this section themselves.
incoming+AAAAFXrQKf8AA3QP92///wABUl2Ukn//uCbIXwoNLnXy94kV@example.com
// The message was sent by bob to the incoming mailbox: $recipient = 'incoming+AAAAFXrQKf8AA3QP92///wABUl2Ukn//uCbIXwoNLnXy94kV@example.com'; $sender = 'bob@example.com'; // Create a new instance of the address manager. $parser = new \core\message\inbound\address_manager(); // First parse the envelope data. $result = $parser->process_envelope($recipient, $sender); // We can check that the data validation passed. if ($result !== \core\message\inbound\address::VALIDATION_SUCCESS) { echo "Some part of the data could not be verified\n"; } else { // We can retrieve the data stored in the message. $data = $result->get_data(); // Get the instance of the handler - this will be the \mod_forum\message\inbound\reply_hander used to define the message originally. $data->get_handler(); // The user key is the user record of the user who the original message was sent to. $data->user; // The datavalue is the integer value that was specified when the message was originally sent. $data->datavalue; }
Handlers
Once a message has been processed by the address manager, it is passed to the handler specified in the address data.
Each Handler belongs to a specific component, and comprises of a class extending \core\message\inbound\handler, which specifies a function to handle any received e-mail messages.
Creating a new Handler
To create a new handler, you must:
- create a class extending the handler class; and
- specify it's default values in that component's db/messageinbound_handlers.php file.
Each new handler must have a unique class name within Moodle and must be loadable using the Moodle class autoloader.
As an example, to create a forum post reply handler called reply_handler:
Component Name | mod_forum |
---|---|
Handler Name | reply_handler |
Namespace | mod_forum\message\inbound |
Class Name | mod_forum\message\inbound\reply_handler |
In mod/forum/db/messageinbound_handlers.php, define the available handlers.
<?php
defined('MOODLE_INTERNAL') || die();
$handlers = array(
array(
'classname' => '\mod_forum\message\inbound\reply_handler',
'enabled' => false,
'validateaddress' => true,
),
);
And define the handler itself in /mod/forum/classes/message/inbound/reply_handler.php:
<?php
namespace mod_forum\message\inbound;
defined('MOODLE_INTERNAL') || die();
class reply_handler extends \core\message\inbound\handler {
// Place the content of the handler here.
}
A handler class must define three abstract functions:
- get_name() - Typically a string returned by get_string() to display as a name in the admin interface;
- get_description() - Typically a string returned by get_string() to display in the admin interface; and
- process_message() - The function called after successful validation of a message, which takes information including the recipient, sender, headers, body, and a list of attachments.
It may optionally define some additional functions:
- allow_validateaddress_change() - To prevent an Moodle administrator from changing whether E-mail address validation is required. Typically this is used to force sender validation.
- allow_enabled_change() - To prevent a Moodle administrator from enabling, or disabling the handler
A new handler must also be defined within the component in lib/db/messageinbound_handlers.php. This array of handlers includes the default settings for the handler used at creation time.
Removing quoted text from email messages
If you want the quoted text to be removed from email messages you can call the method remove_quoted_text from inside your handler as below:-
list ($message, $format) = self::remove_quoted_text($messagedata);
The method will make an educated guess and remove quoted text from the message and return the format and message contents. This method doesn't work perfectly at the moment and MDL-50058 is supposed to improve this.
Validation and Verification
The Inbound Message system performs a step of both validation, and verification.
Note: E-mail is never a secure method of communication, and it is easy to `spoof` the `sender` field when sending an e-mail very easily. As a result, administrators should be fully aware of the consequences when enabling any Inbound Message handler.
When an address is generated, it will be composed of a base64-encoded binary set containing: [handlerid][userid][datavalue][verifiationstring]
- the handlerid is the database ID of the handler used to process the message;
- the userid is the database ID of the user associated with the message;
- the datavalue is an integer value associated with the message; and
- the verifiationstring is part of an md5 hash of a user key, and data key.
A new key will be generated for each individual user. This is unique to the user. A new key will be generated for each piece of data for a handler. This is unique to the handler and datavalue combination.
The keys generated for both the user, and for the handler-data pair are never exposed in the string and are always verified. The userid specified in the address must match the key stored for that user in Moodle; and similarly the datavalue specified in the address must match the key stored for the handler-pair in moodle.
This combination of three pieces of plain-text information, with two pieces of hidden additional information should make it harder for any potential attacks.
Additionally, an administrator can choose whether to compare the e-mail address of the sender against the e-mail address held against a user record. This is enabled by default, but can be disabled by an administrator.
As a further protection, it is possible to specify an expiry timestamp for each handler-datavalue keypair.
Potential attack vectors
Several potential attack vectors exist, and handler authors should determine the optimum solution required. At the very least, it is advisable to recommend sender address comparison, but this is not foolproof on it's own.
As an additional prevention method, the handler could define a further e-mail based verification check whereby on reception of an inboune e-mail, the handler system would:
- store the retrieved message (park it);
- send a new e-mail to the user described in $user containing a link or a further reply message; and
- await for approval from the e-mail.
Spoofed e-mail address
As mentioned above, it is incredibly easy to spoof the Sender field in an e-mail. If the full address is captured by an attacker, then it would be possible to send e-mail as that user and the Inbound Message system would be unable to distinguish the message from a valid address.
Mitigations =
Prevention
- When creating keys, specify an appropriate expiry time for that key pair
- When sending e-mail within Moodle, only use the Reply-To field as this is not typically exposed when a message is forwarded to a third-party
- Provide information to users advising against forwarding of e-mail
Damage Control
- Expire any affected keys
Brute force attack of e-mail accounts
As with any system of this nature (including passwords), it is possible to apply a brute force attack. It would be possible to reverse engineer the e-mail address for a known user, and then recompile it with a range of combinations.
With the proposed length of the verification has (24 characters), this provides for 79,228,162,514,264,337,593,543,950,336 combinations of hash.
Prevention
- When creating data keys, specify an appropriate expiry time for that key pair
Damage Control
- Expire any affected keys
Other notes
It is difficult to increase the length of the verification hash. At present the hash is 24 characters which makes the maximum length of the subaddress 48 characters, leaving space for 15 characters in the mailbox part of the address. Although it would be possible to increase the length of an address, doing so would invalidate all previously used addresses.