SMS::Handler::Email - Process Email related commands


  use SMS::Handler::Email;

  my $h = SMS::Handler::Email->new(-queue => $queue_obj,
                                   -state => $ref_to_hash,
                                   -secret => $my_secret_phrase,
                                   -addr => '9.9.5551212',
                                   -pop => '',
                                   -smtp => '',
                                   -maxlen => 160,
                                   -maxfetch => 1024,
                                   -compact => 1,
                                   -spamcheck => $obj,
                                   -cmds => { ... },
                                   -help => { ... },
                                   -maxspam => 10,

 $h->handle({ ... });


This module implements a simple responder class. It will respond to any message directed to the specified phone number, with the specified message.

The Email message is assumed to be in ISO-8859-1 (Latin1) encoding. Mappings are provided to convert the messages to a safe 7-Bit character set which is believed to be compatible with any SMS receiver. This mapping is lossy in the sense that accents and special characters are converted to a close but incorrect representation. For instance, an a with a tilde is converted to a plain a.


The following commands are supported in the first line of the SMS. Commands can be abbreviated to any unique substring. The first line can be separated by the rest of the message either with a new-line or two consecutive space characters.

.ACCOUNT login password

Associates the given account with the source address of the SMS. Further commands coming from this address are attempted with these supplied credentials, which are the login or username and password of the POP server.


Checks all the messages in the mailbox looking for spam. This requires that a spamcheck item be passed to ->new() at object creation time. A specially formatted response message, suitable to remove all the SPAM messages will be returned.

If this command is followed by the ! symbol, messages recognized as SPAM will be erased automatically.

.SEND to subject

Sends the remainder of the SMS as a message to the address(es) specified in the to field. Multiple addresses can be specified by separating them with commas. No spaces are allowed in the addresses.

Before the actual sending of the message, a POP authentication is attempted. Only if this authentication succeeds will the message be sent.


Retrieves the current list of messages in the POP server.


Deletes the message msg from the POP server. When omitting msg, the command will refer to the most recent message. 0 is a synonim to 1.

.REPLY msg

Replies to the message specified by msg. When omitting msg, the command will refer to the most recent message. 0 is a synonim to 1.

.ALL msg

Replies to the message specified by msg. When omitting msg, the command will refer to the most recent message. 0 is a synonim to 1. All recipients of the original message are copied of the response.

.FORWARD msg to

Forwards the message specified by msg to the addresses specified in to. When omitting msg, the command will refer to the most recent message. 0 is a synonim to 1.

.GET msg [block]

Retrieves the message msg from the POP server. Only the first chars of the body are retrieved. If a numeric block is specified, that block of octets is presented to the user. The first block is 1. The first block of the most recent message can be requested by omitting msg and block. msg must be specified in order for block to be specified too. A msg 0 is synonim to 1.

.ALIAS [address] nick

Creates a nick for the user whose address is specified. If no address is specified, erases the nick. Nick names or aliases, are used as shorthand for the complete email address of a user.


Sends a (very) short usage summary.

The variable $SMS::Handler::Email::DefaultLanguage can be used to choose the default language of all the answers.


The help table is a hash stored in %SMS::Handler::Email::Help. Each key of the hash, is a command name. Each corresponding value is the reference to a hash, whose key is a language code and its value is a brief explanation of what the command does in the corresponding language.

Probably it is wise to avoid explanations that use 8 bit characters, as those are not safely handled by all the phones out there.


The commands must supply responses to the user based on its success. In order to support multiple languages, responses are stored in a hash table (%SMS::Handler::Email::Messages). Each key on this hash table correspond to a language tag as described in I18N::LangTags. The corresponding value, is a reference to a hash whose keys are message tags (ie, an identifier for the message) and a message in the required language.

Please see the source code for the specific message identifiers used. Note that you must call init() if this table is changed.

Supported languages must be added to the %SMS::Handler::Email::SupportedLangages hash before calling the init method.

The following methods are provided:


Creates a new SMS::Handler::Email object. It accepts parameters as a number of key / value pairs. The following parameters are supported.

queue => $queue_obj

An object obeying the interface defined in Queue::Dir, where the response message generated by this module will be stored.

state => $ref_to_hash

Reference to a (potentially tie()d) hash where state about the user will be stored. Passwords will be stored in this hash, under the protection of reversible crypto. Therefore, care must be taken to prevent unauthorized access to this.

secret => $my_secret_phrase

A secret phrase used to obscure the passwords stored for the users.

addr => $my_addr

The address assigned to this service, in format. The destination address of the SMS, must match this argument. If this address is left unspecified, the SMS will be accepted no matter what destination address is used.

pop => $your_pop_server

The name or IP address of the POP server.

smtp => $your_smtp_server

The name or IP address of the SMTP server.

maxlen => $max_sms_length

Maximum length of an SMS. Defaults to 160.

maxfetch => $max_message_length

The amount of bytes to fetch from the body of the email. Defaults to 1024 bytes.

compact => $fold_whitespace

If set to a true value (the default) forces successions of whitespace to be folded into single spaces. This generally improves readability of the SMS.

spamcheck => $obj

If passed, this is assumed to be an object supporting a ->check() method as described in Mail::SpamAssassin. This is used to test fetched messages for SPAM-iness.

cmds -> $hashref

Allows the specification of a new command table which overrides the default.

maxspam -> $max

Defines the maximum number of messages to check for spamminess for each CHECK command. Defaults to test all the messages. Note that checking a large number of messages at once can take very long.


Process the given SMS. Commands are taken from a dispatch table and appropiate handlers are called. Commands must be in the first line of the SMS.

An exception to this rule, is the fancy syntax supported by some phones, that looks like

    you@some.where(subject)this is the message body
    you@some.where (subject) this is the message body
    you(subject)this is the message body
    you (subject) this is the message body

This syntax is transparently converted to our command based syntax.


Produce an error when a given command does not exist. Causes the current SMS to be discarded from the queue.


Handler method for the ACCOUNT command. Note that access to the underlying hash ($self->{state}) must be done in a manner that MLDBM likes, as most likely the passed hash is tied using this class.

Also, the implementation must assume that other items of state information might be stored in that hash. Those items should be preserved.


Handler method for the ALIAS command.


Handler for setting the interface language.


Handler method for the SEND command.


Handler method for the LIST command.


Handler method for the HELP command. Sends a SMS message for each supported command, containing the help messages defined.


Handler method for the DELETE command.


Handler method for the REPLY command.


Handler method for the ALL command.


Handler method for the FORWARD command.


Handler method for the GET command.


Handler method for the CHECK command. Only makes sense if ->new() is called with spamcheck defined. Currently a noop.


To further enhance the customization of this class, the following functions can be overriden to tweak the behavior of this module.

fixup_state($self, $source)

This method is invoked after issuing the call to ->_fetch_state() (and failing). Its main purpose is to allow the definition of default credentials for every user. It can return a false value (the default) to cause an error to be reported when no credentials are available. This function should provide values to $self->{_state}. It is called with the source address of the cellular phone in the format NPI.TON.NUMBER.

fixup_phone($self, $hsms, $phone)

This function is used to convert a number in NPI.TON.NUMBER format to a phone number as expected by cellular users. It must return the phone number as expected by the user.

fixup_sms($self, $hsms)

This function is invoked from within the ->handle method, before dispatching to the handlers. This can be used to perform custom transformations in the messages before processing. The default method, provides a translation from Nokia-like syntax into the expected .SEND syntax.


The encription of the user passwords is intended to prevent a casual observer looking at the hash, from getting the passwords. Since the crypto is both, simplistic and reversible, you should assume that any compromise of the hash containing the passwords lead directly to password compromise.


None by default.


This code comes with no warranty of any kind. The author cannot be held liable for anything arising of the use of this code under no circumstances.

This code is released under the terms and conditions of the GPL. Please see the file LICENSE that accompains this distribution for more specific information.

This code is (c) 2002 Luis E. Muñoz.


$Log:,v $ Revision 1.55 2003/03/13 20:41:54 lem Fixed case where a command was not followed by any options or any whitespace

Revision 1.54 2003/03/10 22:07:31 lem Messages were being mixed under certain conditions

Revision 1.53 2003/03/09 16:24:52 lem Patch mpicone

Revision 1.52 2003/02/26 14:50:46 lem Improved readability of replies and forwards.

Revision 1.51 2003/02/26 02:45:18 lem Changed .ALIAS order as per compadre's patch

Revision 1.50 2003/02/19 15:25:12 lem Fix for _setup_decoder bug

Revision 1.49 2003/02/18 20:50:30 lem Added patch from luis

Revision 1.48 2003/02/18 15:57:29 lem Reinstate msg number 0 == 1

Revision 1.47 2003/02/18 15:52:35 lem Omitting the message number, tries to use the latest message

Revision 1.46 2003/02/17 18:48:28 lem First attempt at handling multipart/alternative correctly

Revision 1.45 2003/02/13 13:12:23 lem Fix typo in the docs. Added fixup_sms(). Changed the calling protocol for the rest of the remaining fixup_* methods (more power to them).

Revision 1.44 2003/02/12 15:22:39 lem Patch from compadre. The help can be passed to ->new() and also, fixed a typo in the docs

Revision 1.43 2003/02/12 14:38:02 lem Improved clean-up of attachments left behind

Revision 1.42 2003/02/12 00:50:33 lem Message truncation is now working

Revision 1.41 2003/02/11 15:45:04 lem Added fixup_phone and fixup_state

Revision 1.40 2003/02/10 17:34:01 lem Added .ALL

Revision 1.39 2003/02/06 19:49:42 lem Various variables and refs factored in the object

Revision 1.38 2003/02/04 21:33:16 lem Added ! to .REPLY and .FORWARD. Testing is needed

Revision 1.37 2003/02/04 16:01:26 lem Omitting msg now means "last". 0 == 1

Revision 1.36 2003/01/28 18:10:47 lem Added lowercasing when the message body is in ALL CAPS. Added display of the origin phone number when the email was sent from a cellular.

Revision 1.35 2003/01/27 20:44:27 lem .ACCOUNT now stores the date in which it executed in the hash

Revision 1.34 2003/01/14 20:32:34 lem Got rid of Net::SMPP::XML

Revision 1.33 2003/01/08 02:39:03 lem Body was not being updated by _CMD_SEND. "Nokia" format send command is now properly understood. First segment of the message is being sent by .FORWARD and .REPLY.

Revision 1.32 2003/01/05 00:49:08 lem It seems that the bug is not in HTML::Parser either. Taking the md5_hex() of its input before invoking ->parse() seems to get rid of the problem under darwin. More testing is needed to find out where the bug manifests. I am guessing that Perl might be the culprit.

Revision 1.31 2003/01/04 03:38:03 lem Current 8-bit conversion bug has been traced to HTML::Parser. Unable to reproduce in smaller sample program. Testing needed in another platform. The HTML::Parser, Unicode::Map8 and MIME::Decode as well as other items are now kept in $self and initialized only once (and reused) when possible.

Revision 1.30 2003/01/04 00:15:31 lem Fixed some bugs related to stopping the HTML parser when the desired chunk has been parsed.

Revision 1.29 2003/01/03 01:33:44 lem Added .ALIAS. Fixed minor bug with alternate syntax for .SEND.

Revision 1.28 2003/01/02 18:17:26 lem Added -spammax to control how many messages can be check for spamminess

Revision 1.27 2002/12/31 17:08:33 lem Minor fixes in error messages

Revision 1.26 2002/12/31 15:46:10 lem Introduced Map8 workaround using tr///. Looks ugly but seems to work

Revision 1.25 2002/12/31 05:27:16 lem Documented the Unicode::Map8 bug (?) in a newly added BUGS section

Revision 1.24 2002/12/31 05:15:15 lem Factoring of code that access ->{state} (_fetch_state and _store_state). GET now can fetch message chunks to read in entirely. Minor fix in the reply message legend.

Revision 1.23 2002/12/29 22:11:54 lem Improved decoding of MIME QP. Non-MIME messages are now handled by MIME::Parser. Dropped superfluous MIME module

Revision 1.22 2002/12/27 20:10:40 lem Updated docs

Revision 1.21 2002/12/27 19:43:42 lem Added ::Dispatcher and ::Utils to better distribute code. This should make easier the writting of new methods easier

Revision 1.20 2002/12/26 19:11:31 lem Two spaces can be used instead of \n to separate a command from the body of the SMS

Revision 1.19 2002/12/24 08:21:54 lem $Debug = 0. Improved HTML parsing by ignoring <script> and <style> stuff. Better message truncation support.

Revision 1.18 2002/12/23 06:36:04 lem Huge rewrite of the message parsing. Now MIME is handled properly, including fancy multipart messages. Attachments are detected and signalled when within the message size boundary. Message fetching process is lighter and uses on-disk files for caching (and to reduce memory hungriness). .CHECK is more efficient now.

Revision 1.17 2002/12/23 03:17:49 lem Wrapped call to check_message_text() in a special eval{} to avoid the nasty warns of non-essential modules being loaded by Mail::SpamAssassin

Revision 1.16 2002/12/23 01:18:13 lem Added .CHECK command. Also updated the license to GPL

Revision 1.15 2002/12/22 19:04:18 lem Changed license to GPL. Preliminary SPAM tagging support. Needs testing

Revision 1.14 2002/12/22 04:08:19 lem Added README to MANIFEST. Added .FORWARD. We understand HTML messages now, complete with MIME/QuotedPrintable support. Minor fixes in the treatment of MIME messages in .REPLY and .FORWARD. Included some left-over messages into the multi-language support.

Revision 1.13 2002/12/21 23:29:09 lem Added multilanguage support (en, es). Added .INTERFACE and .HELP for specific commands

Revision 1.12 2002/12/20 01:25:57 lem Changed emails for redistribution

Revision 1.11 2002/12/19 18:44:39 lem MIME-Version must be pushed only once

Revision 1.10 2002/12/19 18:40:31 lem Added .REPLY. Also, added MIME headers to outgoing messages. MIME types are preserved in .REPLY. For .SEND, ISO-8859-1 is assumed

Revision 1.9 2002/12/19 17:12:45 lem Added conditional whitespace folding

Revision 1.8 2002/12/19 16:39:30 lem Added truncation indicator at end of large messages

Revision 1.7 2002/12/19 16:12:21 lem Added Date::Parse. This helps us reduce the size of the Date header, saving space in the SMS

Revision 1.6 2002/12/19 06:00:12 lem Fixed minor issues with regexps. Also improved the foo@bar.baz syntax to allow messages with no subject

Revision 1.5 2002/12/19 05:10:41 lem

- Added foo@bar.baz(subject)body notation through a simple transform

Revision 1.4 2002/12/19 04:54:44 lem Added last() to the result of .LIST

Revision 1.3 2002/12/19 04:43:16 lem

- handle() is now a dispatch handler - Commands are handled through self-contained methods (_CMD_*) - Improved error handling a bit

Revision 1.2 2002/12/18 22:01:46 lem More functionality added. Some is still missing

Revision 1.1 2002/12/18 08:45:13 lem

- Added prereqs for Net::SMTP and Net::POP3 - Added SMS::Handler::Email. Still not completely functional - Added some tests for ::Email


  • It looks like HTML::Parser 3.26 is returning the 8-bit data mungled after its first use. This is currently being investigated and no work-around exists.


Luis E. Muñoz <>


SMS::Handler, Queue::Dir, perl(1).

3 POD Errors

The following errors were encountered while parsing the POD:

Around line 2093:

You forgot a '=back' before '=head2'

Around line 2195:

=back without =over

Around line 2211:

Non-ASCII character seen before =encoding in 'Muñoz.'. Assuming ISO8859-1