class ref name: mass_mail
category-group: email
layer: 11
header file: z_massmail.h

synopsis.
The mass mailer class (" massmail_o ") is an object designed to send out a form letter. It requires a lot of configuration and uses 2 input files. The configuration parameters may be supplied either via an INI file or by [repeatedly] calling "config()" member function.

It can use a form letter (eg 'template file') with embedded PHP source code. In order to do this, you need to have PHP installed on your machine, with the environment variable 'PHPRC' pointing to PHP's home directory (where php.exe is).
See the PHP file object for more information.

You can turn on or off PHP pre-processing, or whether you want to actually send the e-mail (perhaps you are just generating files); you can easily set the MIME type, From: and Reply-To: fields, subject line, and other parameters in an INI file that is supplied to this object prior to invoking run(); or, you can use the config() member function to set these parameters.

In addition to setting parameters, you can subclass from the massmail_o class in order to implement pre- and post-processing functions. In a typical window system at the programmatic-API level, you can set "callback" functions after a window event. Likewise, you can set up functions that are invoked:

  • preprocess_php() - called before PHP pre-processing occurs. There is no previous operation, so the error status variables (my_last_status, my_suberrcode) are always set to 0. The file supplied to this function is the raw, unchanging template file.
    Since this callback function gets called at the start of the loop, it is always called. It does not depend on the value of the 'PHP' [ini file] parameter.
    You can replace the default message printing with your own - do that by providing a line of text in the INI variable "logging/MESSAGE_START=[your text here]". However, this is a kludgy, inferior technique - unless you don't mind printing the same message over and over again. You can turn off printing anything with "logging/PRINT_MSG_START=NO". Or, you can subclass and fill in your own function - in which case, you can do whatever you want.
  • postprocess_php() - after PHP pre-processing occurs. The file supplied is that of the output from the PHP CLI (SAPI).
    If the 'PHP' [ini file] parameter is not set to YES, this function will not be called.
  • preprocess_msg() - this function is called before an e-mail is sent. The input is in the form of a [possibly very large] string object, not a file. Note that there is almost nothing going on between postprocess_php() and preprocess_msg(). However, for sake of completeness (consistency?), this function is included. Also, between the two functions there is Vettrasoft-custom keyword replacement processing (controlled as a YES/NO switch in the INI file, "run/VSKW").
    If the 'SEND' [ini file] parameter is not set to YES, this function will not be called.
  • postprocess_msg() - this is invoked after an e-mail is sent. A string object is supplied to this function. It contains the final, actual message text. If the 'SEND' [ini file] parameter is not set to YES, this function will not be called.
    As with preprocess_php(), the default function here prints a message. You can turn this message dump off with "logging/PRINT_MSG_FINISH=NO". Or, you can supply your own [static] message, like so:
    logging/MESSAGE_FINISH=[your text here]
    And, of course, you can implement your own by subclassing and making your own postprocess_msg(), in which case the message printing would be replaced by whatever you want to do (isn't that what C++ is all about?).

These functions allow you to add hooks before and after key points in the mass mailing operation, allowing you to do things such as storing info to a database, or copying the letter (perhaps for backup or analysis). The "callbacks" are implemented as [non-pure] virtual functions. Thus, you can use the object "as-is", or, in order to take advantage of these [optional] hooks, you would need to make a subclass from the massmail_o class. The parameters you are provided with is the current file or string object being processed, and the current databag. In addition, you have access to the internal variable 'my_last_status', which is set to 0 if the previous operation (if there is one) succeeded, or -1 if it failed.

description.
The mass mail class wraps up the entire operation of sending repeated emails into a single object. Everything that it does is encapsulated into the single function run(). Inside this function is a loop which fetches recipients from a file. The loop terminates when the entire file is processed. It can be summarized by this diagram:

massmail event flow

The numbered arrows can be thought of as a UML event diagram:

  1. The massmail object opens the INI file and loads the data, thus configuring itself.

  2. The form letter is opened.

  3. The recipient list file is opened. Each databag is fetched, one at a time.

  4. The form letter is copied to a temp file, which is then handed over to the PHP processor.

  5. the PHP processor generates an output file.

  6. The output file is opened and read by the massmail object.

  7. The resultant text (stored inside a string object) is handed over to the Mail Transport Agent, eg, the mail server.

  8. The MTA forwards the message.
The massmail_o class relies heavily on [a single instance of] the email_address_o class. Each parameter in the INI file can also be set via the config() member function. The parameter name used in config() is the same name as used in the INI file (without the group name). It can be lower-case or the same as that of the INI file (by convention, the INI name is in upper-case). For example, both of these set the e-mail 'From' field:
via the INI file:

  FROM=gorth.durak@gmail.com

via config():

  #include "z_paramstring.h"
  paramstring_o ps;
  ps = "FROM=\"gorth.durak@gmail.com\"";
  massmail_o mmx;
  mmx.config (ps);
config() can also be used to set on/off certain options:
  • zFlag_MM_USEINI - use/don't use INI; keyword is "USE_INI". Default if "NO". Note that this option is easily over-ruled, simply by invoking the member function /I>set_ini() with a valid INI file path.
  • zFlag_MM_DOSEND - send/don't e-mail. if not sending, this is similar to doing a dry run. It can be used to just generate the form letter output files. Keyword is "DO_SEND". Default is "YES".
  • zFlag_MM_USEPHP - use / don't use PHP pre-processing. If turned off, the form letters should not have PHP embedded source code, as any PHP CLI SAPI will not be invoked. Keyword is "USE_PHP". Default value is "NO".
  • zFlag_MM_USEEMO - Use / don't use email_address_o (the 'e-mail address object') for sending e-mails. Keyword is "USE_EMO". Default value is YES.
  • zFlag_MM_USESENDMAIL - use / don't use sendmail for sending e-mails. This flag is applicable only on unix systems. Also, it is not relevant if zFlag_MM_DOSEND is turned off. Keyword is "USE_SENDMAIL". Default value is "YES".

In all of the cases above, the value must be either "YES" or "NO". For example, this code sliver turns off sending, and turns on PHP:

  massmail_o mmx;
  paramstring_o ps;
  ps = "DO_SEND=YES USE_PHP=YES";
  mmx.config(ps);

When setting the "From:" field, use the raw, unmodified e-mail address, without any name prepended. Do not put it in quotes. Keep it simple:

FROM=j.blow@yahoo.com
The following line is WRONG:
FROM=Joe Blow         # ...Wrong! Error!!

For setting the "Reply-To:" field, a special syntax is used, that is, a slight modification from the actual string is required. In the INI file, for the "REPLYTO" fields (in the 'letter' group), if using a name and e-mail address, the name part must not be in quotes, and the e-mail address part must be in angle-brackets. Suppose you want the end result (in the actual message) to look like this:

Reply-to: "Gorth Le'Rock" 
Leave out the quotes. They will be added (in the member function config()). This quirk is necessary, due to the nature of how the INI file object processes an INI file. It pulls in a quote as the value of the keyword, or, if the first non-blank character is not a [single or double] quote, anything up to a comment character ("#") or end-of-line. So the following are ok: FROM=gorth.durak@gmail.com REPLYTO=Gorth Le'Rock The following is not ok / it won't work (the e-mail address will be omitted, if you do it this way): REPLYTO="Gorth Le'Rock" This is applicable if setting these values either via config(), or via the INI file.

The parameters for this class is summarized in the following table. All parameters that take a string as a name have default values of empty strings (""), unless otherwise noted.

name values description
database
USE_DB YES, NO
default: YES
If NO, writing 'event' notes to a database is disabled.
SERVER [name-string] name of the database server (if applicable)
DATABASE [name-string] the database name.
ACCOUNT [name-string] database [user] account name
PASSWORD [text-string] database password for user account.
files
RECIPIENTS [file] full path name of file containing e-mail recipients; by Vettrasoft file convention, the extension is ".bag"
FORMLETTER [file] full path (directory + file name) of template/form file
ATTACHMENT [file] full path (directory + file name) of any file to attach. only 1 file is allowed, in this case.
INTERIM [file] full path (directory + file name) for the temporary output file. You should provide this.
run
WET, IS_WET YES, NO
default: YES
Whether or not to do a "wet run". This is almost always 'YES'. Note, you can use either keyword.
DO_SEND, SEND YES, NO
default: YES
If set to 'NO', the [generated] form letter will not be e-mailed.
TARGET BIZ_ONE | BIZ_ALL | WORKER | ALL_WORKERS | ALL
default: BIZ_ALL
Since a business can have workers, each with their own set of e-mails, or multiple e-mails, this dictates which e-mails are to be sent the letter. The meanings of the keywords:
 
BIZ_ONE - send to the first business e-mail (only 1, max). If there is none, zero mails will be sent (irregardless of any employees).
BIZ_ALL - send to all the business e-mail addresses.
WORKER - send an e-mail message to [at most] the first worker. If there are no workers, or no worker e-mail addresses, none will be sent.
ALL_WORKERS - send to all employee e-mail addresses (this can be zero).
ALL - send to all e-mail addresses associated with the business.
PHP, USE_PHP YES, NO
default: NO
If 'NO', the PHP CLI preprocessor will be skipped (a significant time savings).
VSKW YES, NO
default: YES
Whether or not to invoke Vettrasoft keyword (VSKW: "Vettrasoft Key-Word") pre-processing. Set it to NO if you don't want to use this pre-processing step applid to the files.
EMO, USE_EMO YES, NO
default: YES
Whether or not to use the email_address_o for sending e-mails. Leave this set to "YES" (not applicable if "SEND=NO")
SENDMAIL, USE_SENDMAIL YES, NO
default: YES
[unix only] if YES, "sendmail" will be used to send the mail; otherwise, the "mail" program.
PAUSE [n]
default: 0
"[n]" is simply the number of seconds to wait between iterations (use just a number, ie, "PAUSE=5"
ABORT_BAGERR YES, NO
default: NO
Abort run if an error is encountered in the current databag. This is invariably if there is no e-mail address field ("arpa").
ABORT_PHPERR YES, NO
default: NO
Abort the run if an error occurs during PHP processing. This is obviously irrelevant if "PHP=NO". If the PHP SAPI errors out, the program will terminate, instead of just skipping the current databag (eg, recipient).
ABORT_SENDERR YES, NO
default: YES
Abort run if there is an error while trying to send the e-mail message.
BAG_TOPMARKER [any short text] this is a sequence of characters, on its own line, that [if set] is used to precede the databag containing a business entry. It is used in conjunction with BAG_BOTMARKER and in opposition to BAG_SEPARATOR (set either a top-bottom pair or the separator string, not both)
BAG_BOTMARKER [any short text] this is a sequence of characters, found on its own line, used to terminate a business entry. It is used in conjunction with BAG_TOPMARKER and in opposition to BAG_SEPARATOR (set either a top-bottom pair or the separator string, not both)
BAG_SEPARATOR default: #------o this is a sequence of characters, found on its own line, that is used to separate databag entries in the source stream. By default, this is set, so to use the parameter pair BAG_TOPMARKER and BAG_BOTMARKER , make sure this parameter is included in your INI file and set this item to an empty string (nothing following the "=").
logging
VOLUME [n]
default: 0
Set the program debugging level to 'n'. This value must be from 0 to 100 (inclusive). See the reference manual page for (quickdirt) rundriver object for details.
TRACE YES, NO
default: NO
Set the program debugging level to 'n'. This value must be in 0 to 100 (inclusive). See the reference manual page for (quickdirt) rundriver object for detils.
LOGSEND YES, NO
default: NO
log the event to the DB?
PRINT_MSG_START YES, NO
default: YES
whether or not to print the default message in preprocess_php().
PRINT_MSG_FINISH YES, NO
default: YES
whether or not to print the default message in postprocess_msg().
POPUP_ERRORS YES, NO
default: NO
If an error occurs, the corresponding message will be put into a pop-up window, instead of printed to the console. The application will block.
POPUP_EXIT YES, NO
default: NO
When the program is about to exit, a message will be put into a pop-up window, instead of printed to the console. Thus, you have a very visible notification of the end of a run. The application will block.
MESSAGE_START [text]
If this is set (to a non-empty string), the default text printed in "preprocess_php()" will be replaced by this text. Note that no dynamic information (e-mail address, loop index number) can be printed this way.
MESSAGE_FINISH [text] If this is set (to a non-empty string), the default text printed in "preprocess_msg()" will be replaced by this text. Note that no dynamic information will be printed this way.
MESSSAGE_EXIT [text] If this is set (to a non-empty string), the text will be printed out when the program exits, either to the console (by default), or to a pop-up window (if POPUP_EXIT=YES).
MSG_INTRO [text]
default: "[[MASSMAIL]] "
If this is set (to a non-empty string), the text will be printed as the 'starting prompt' upon error or notification messages. This text is intended to be very small (< 20 chars or so). If not set, the default prompt-string is "[[MASSMAIL]]".
letter
FROM [email-addr] enter just a valid [mandatory] e-mail address for the message 'From:' field (no brackets)
REPLYTO [text] use either just an e-mail address, or just a name (not quoted), or an unquoted name followed by an e-mail address.
SUBJECT [1-line-text] This is the e-mail message subject line text.
EVENT [text]
MIMETYPE [string]
default: "text/plain"
Enter the text for the MIME type, such as text/html or text/plain (without any quotes).
DATEFORMAT [string]
default: "%b %d, %Y"
This is used for setting the format of dates, used by the Vettrasoft custom keyword replacement (VSKW=YES). The default value is given by the macro 'zMM_DEFAULT_DATEFMT'. This may be omitted; it is used only if VSKW=YES. if VSKW=NO.
mta
MTA_NAME [string] the name of the e-mail server to connect to (such as "smtp.gmail.com")
MTA_PORT [number]
default: 25
The server port number to use for connecting to the e-mail server ("Mail Transport Agent"). The macro label for the default value is 'zMM_DEFAULT_SENDPORT'.
MTA_ENCRYPTION [keyword]
default: NONE
should be one of: NONE, BASIC, SSL. If omitted, defaults to "NONE".
MTA_ACCOUNT [string] The log-in account string for the e-mail server.
MTA_PASSWORD [string] The log-in password for the e-mail server.

A note about "VSKW" mode:If you set the INI parameter 'run/VSWK' (a legacy search-replace thing), you can apply transformations like so:
$::date
$::who
$arpa

$::build_salutation
This is a message from George Bush. Just because I am not officially the president of America doesn't mean I can't control you. I need to know everything about you, including how often you have sex, with who, and what sex the person(s) is/are. If you fail to comply, the power of the American federal government will fall on your disobiedent ass, and you will spend the rest of your life in one of our Supermax prisons. Sincerely, G. Bush (top dictator) punkhol@ex-prs.whitehouse.gov

Thus, given a databag such as this:
# :start-databag:
target
(
    who
    (
      worker ( name ( first Michael last Brown ) title victim )
    )
    phone <"+1 (314) 522-3100" >
    email "mbrown@deadguys-butwhy.org"
)
# :end-databag:

Can generate output such as this:
Jan 18, 2016
Michael Brown
mbrown@deadguys-butwhy.org

Dear Mr. Brown:
This is a message from George Bush. Just because I am not officially the president of America doesn't mean I can't control you. ... Sincerely, G. Bush (top dictator) punkhol@ex-prs.whitehouse.gov

member functions (primary)

massmail_o()
SIGNATURE: massmail_o ()
SYNOPSIS: creates a a new, 'empty' massmail object. All of its settings are at default values after this construction.
 

destructor
SIGNATURE: ~massmail_o ()
SYNOPSIS: virtual destructor. The massmail object instance is reset.
 

config()
SIGNATURE: int config (paramstring_o &ps, int *pi = NULL)
SYNOPSIS:
This member function is the workhorse of configuring a massmail object prior to calling run(). Any of the parameters specified in the main table above can be passed to this function (via input variable "ps"). Multiple name-value pairs can be used, separated by a space. Values with embedded punctuation or whitespace must be quote-wrapped (precede a double-quote by a back-slash {standard c programming}).
Example:

    massmail_o mm;
    mm.config("FORMLETTER=\"readme.txt\" RECIPIENTS=\"targets.bag\");
    mm.config("MIMETYPE=\"text/plain\" PHP=NO");
    mm.run();
This code sliver is not sufficient to actually work. The massmail object requires many parameters to be preconfigured in order to be able to run successfully. As can be seen from the example, config() can be called repeatedly, with a variable number of key-value pairs embedded in the 'ps' parameter.
PARAMETERS
  • pi: [optional] error indicator variable. Its values:
    0: all ok
    1: unknown keyword encountered
    2: YES | NO string expected, not found
    3: other flag value issue
    4: unknown (eg, illegal) encryption type given
  •  

    set_volume()
    SIGNATURE: int set_volume (int x)
    SYNOPSIS:
    sets the debugging/tracing output volume level. The value of 'x' must be in the range [0..100], inclusive. The volume levels embedded in this object include:
    10: error messages printed (symbolic constant 'zMM_Volume_FatalErr');
    20: "followup" (post-event) error messages printed (symbolic constant 'zMM_Intolerable_Volume ');
    30: default messages in "preprocess_php()" emitted; custom messages in "postprocess_msg()" printed;
    35: successful send messages in "postprocess_msg()" emitted;
    45: post-send "trace" message printed ('zMM_Volume_BasicMsg')
    RETURNS:
    0: volume successfully set.
    -1: volume not set - inputtd value was out of range.
     

    set_ini()
    SIGNATURE: int set_ini (const string_o &spath, int *pi = NULL)
    SYNOPSIS:
    sets the file name (and path, if one is provided in 'spath') of the INI file. Using this function is optional, and should be used if the object's configuration is to be specified via an INI file. This is "optional" because you can use config() to also configure the object. This routine passes the variable 'spath' to a file object, which then verifies if the file exists. If it is not found, or cannot be accessed, this is not considered an error, but the output error flag will be set to indicate this fact.
    If this routine succeeds, the myflags bit 'zFlag_MM_USE_INI' will be set, which will allow load_ini() to proceed.
    PARAMETERS

  • pi: [optional] error indicator variable. Its values:
    0: all ok, file set
    1: INI file not found (warning only)
    2: INI file name was previously set (warning only)
  • RETURNS: 0
     

    load_ini()
    SIGNATURE: int load_ini (int *pi)
    SYNOPSIS:
    this member function will load the contents of an INI file. The object will be configured according to the parameters found in the file. This routine can be used in conjunction with config(). The order does not matter. Successive calls to load_ini() will over-write any previously set values. Any parameters omitted from the INI file can be set via config().
    This function can be called explicitly, or run() will call it automatically, if an INI file was specified (via set_init()). If called earlier, and "run()" has not been done, this is considered a warning, and the output error variable ('pi') will be set - there is no normallly good reason to call "load_ini()" more than once.
    PARAMETERS

  • pi: [optional] error indicator variable. Its values:
    0: all ok
    1: ini file is not to be used! ('use_ini' is FALSE)
    2: ini file load failure; probably bad syntax in the file
    3: "load_ini()" called earlier [warning only]
    4: 'i' out of bounds (1st loop). should never happen.. unless 'i' value increased and out of sync with # of elements in the ini file.
    5: 'i' out of bounds (2nd loop). same reason as *pie = 4. This can never actually happen, because the same error is handled where output value '4' is set.
    6: YES | NO string expected, not found
    7: [PANIC] "map2_idx_str()" internal error (should not happen)
    8: [PANIC] "config()" call failed
  • RETURNS:
    0: INI file successfully loaded.
    -1: INI file not loaded (See 'pi' for reasons why)
     

    attach_file()
    SIGNATURE: int attach_file (const file_o &f, int *pi = NULL)
    SYNOPSIS:
    This adds an attachment to the e-mail message to send. This function can be called repeatedly to attach more than 1 file. NOte that when using the INI file, only 1 file can be attached.
    RETURNS: 0
     

    volume()
    SIGNATURE: int volume () const
    SYNOPSIS: returns the value of the volume set by set_volume().
    RETURNS: 0
    TRAITS: this member function is inlined.
     

    reset()
    SIGNATURE: int reset()
    SYNOPSIS:
    resets the massmail object to its default, at-construction-state [eg, default] values. See the main table on this page for a list of the massmail parameter default values.
    RETURNS: 0
     

    run()
    SIGNATURE: int run (int *pi)
    SYNOPSIS:
    processes a list of recipients to send each an e-mail. This member function is the only funtion that "does work". See the main description section on this page for more information about what this object does.
    This function invokes "pre_check()" to make sure things are in order for doing a run: recipient list file and form letter file must exist; and if using PHP, the directory for the output file from the PHP CLI must exist.
    PARAMETERS

  • pi: [mandatory] error indicator variable. Its values:
    0: all ok
    1: no recipient list (file). This value is set in "pre_check()".
    2: no [input] form letter (file) was specified or found. This value is set in "pre_check()".
    3: directory for the intermediate [post-PHP] file doesn't exist {from pre_check()}.
    4: temporary (work) file name was not set - this should have been auto-generated, if not explicitly set {from pre_check()}.
    5: INI file could not be opened (bad path?)
    zErr_Resource_Unavail: database could not be opened.
  • RETURNS:
    0: recipient list successfully processed.
    -1: an error occurred during the run. see 'pi' for info why.
     

    preprocess_php()
    SIGNATURE: int preprocess_php (const file_o &f, rec_dbag_o &bag)
    SYNOPSIS:
    This function is one of a series of 4 virtual functions allowing you the option of overriding the default behavior (which in some cases is nothing, and other cases a message is printed). In order to implement your own reinterpretation of this function, a subclass must be created. Typically this subclass is a minimal class with the only these virtual functions explictly defined.
    This function provides a "hook" where the application can do something prior to a file being submitted to PHP for processing. It is always called (whether the default version or your own). See the main description section for more information on this function and the other three associated virtual functions.
    The default action of this function specifically is to print 'GOT ANOTHER RECIPIENT (# [n] - "[email-address]"', where '[n]' is the count number and '[email-address]' is the current recipient e-mail address. You can shut off or change printing this message in many ways:

    1. set the "logging/PRINT_MSG_START" value in the INI file to NO
    2. call config() with the "PRINT_MSG_START" value set to NO
    3. set the INI value "logging/MESSAGE_START" to some text, eg, any non-blank characters.
    4. use config() with the paramstring_o value "MESSAGE_START", providing some text, eg:
           massmail_o x;
           x.config("MESSAGE_START=\"print this!\"");"
           
    5. set the volume to 36 or higher

    PARAMETERS
    • f: the file object for the template file.
    • bag: the [recursive] databag containing the data from the recipient list file. The contents of 'bag' is complete dataset for the current recipient being processed.
    RETURNS: 0
     

    postprocess_php()
    SIGNATURE: int postprocess_php (const file_o &f, rec_dbag_o &bag)
    SYNOPSIS:
    This function is one of a series of 4 virtual functions allowing you the option of overriding the default behavior. In order to implement your own function, a subclass must be created. Typically this subclass is a minimal class with the only these virtual functions explictly defined.
    This function provides a "hook" where the application can do something after a file has been being submitted to PHP for processing. It differs from preprocess_php() in that it is provided a file object with the contents of the form letter after PHP processing. If PHP processing is turned off, the file object points to the original template file. However, if off, this function will not be called . See the main description section for more information on this function and the other three associated virtual functions.
    The default action of this function specifically is nothing. That is, this function does absolutely nothing; it simply returns 0. Furthermore, it is not even called unless PHP (or USE_PHP) is set to YES. The default value of PHP is NO. The file should not be modified, else serious damage can result.
    PARAMETERS

    • f: the file object for the template file.
    • bag: the [recursive] databag containing the data from the recipient list file. The contents of 'bag' is complete dataset for the current recipient being processed.
    RETURNS: 0
     

    preprocess_msg()
    SIGNATURE: int preprocess_msg (const string_o &msg, rec_dbag_o &bag)
    SYNOPSIS:
    This function is one of a series of 4 virtual functions, thus allowing you the option of overriding its default behavior. This function provides a "hook" where the application can do something prior to a message being sent. It is called only if the SEND parameter is set to YES (this is so by default). The default action of this function specifically is nothing. That is, this function does absolutely nothing; it simply returns 0.
    PARAMETERS

    • msg: a string object containing the text to be sent via e-mail.
    • bag: the [recursive] databag containing the data from the recipient list file. The contents of 'bag' is the complete dataset for the current recipient being processed.
    RETURNS: 0
     

    postprocess_msg()
    SIGNATURE: int postprocess_msg (const string_o &msg, rec_dbag_o &bag)
    SYNOPSIS:
    This function is one of a series of 4 virtual functions that provide the application a "hook" where the application can do something after to an e-mail has been sent. This is done just prior to the end of the procssing cycle for the current recipient. It is always called.
    The default action of this specific function is to print a line to the console [stdout] like: '"[addr]" - letter sent.' where [addr] is the current e-mail address. This is done if the send was successful. If the send failed, a message like this one is printed to stdout:

    [addr]; last error message: "[error text]"
    
    '[error text]' is provided by the OS mail transport system. In the default function case (no subclassing done), there are many ways to turn off or modify console message printing. See the entry for preprocess_php() for a list of alternatives. It can be shut off by setting the parameter 'PRINT_MSG_FINISH' to 'NO'. You can change the message text to your own by setting the parameter MESSAGE_FINISH.
    PARAMETERS
    • msg: a string object containing the text what as sent via e-mail.
    • bag: the [recursive] databag containing the data from the recipient list file. The contents of 'bag' is a complete dataset for the current recipient being processed.
    RETURNS: 0
     

    curr_count()
    SIGNATURE: count_t curr_count ()
    SYNOPSIS: returns the index value of the current recipient. The first recipient has value 0.
    TRAITS: this member function is inlined.
     

    usage.
    The steps required to send e-mail using this object, in the simplest case, breaks down into these steps:

    1. set up the INI file that the object will read.

    2. write a form letter.

    3. set up the list of recipients.

    4. write a program using the object.

    5. run the program.

    [1] setting up the INI file.

    [2] writing the letter to send.
    This can be as simple as writing a letter. However, it can be very complex because you can write a document written with embedded PHP, or even entirely in PHP. A PHP-based document allows you to tailor the final text to the person, the business, or just about any set of parameters applicable to the letter. The massmail_o instance provides a mechanism for pushing the data of the business to the letter. How this is done is detailed in the PHP file object . You should get familiar with its operation in order to take advantage of the PHP processing behaviour. For those of you in a hurry, a [very minimal] Quick-Start boilerplate example is presented here:

    The variables from the simple databag items inside a recursive databag are forwarded to the PHP processor. The databag comes from the current business entry being processed. Only simple items (no arrays, lists, or sub-databags) are translated into the PHP file. For a business, this includes the business name (databag path: full_name); and other fields such as id, what, note, or found. Not only top-level simple items are processed: all simple databags in the entire recursive databag. Thus given this business, in databag format:

    # :start-databag:
    target
    (
        id 18900309
        full_name Brainbench
        who
        (
          worker ( name ( first Vyacheslav last Molotov ) title lapdog )
        )
        phone <"+1 (703) 674-3500" "+1 (703) 674-3332">
    )
    # :end-databag:
    
    In addition to the top-level, simple items id and full_name, the worker's first and last name, and title are simple databag items, so they too are forwarded to the PHP file. Normally, a databag item such as last name is accessed by a space-separated path like so:
    string_o lnam = bag.get("who worker name last");    // returns Molotov
    
    To make variable processing a little cleaner inside a PHP environment, these spaces are converted to dashes ('-'):
    $lnam = $_SERVER['who-worker-name-last'];
    
    Expanding on this, you should be able to drop the following code into a text file (it can end in .txt or .php - whatever you prefer):
    <?PHP
    $biz_name = $_SERVER['full_name'];
    $fname    = $_SERVER['who-worker-name-first'];
    $lname    = $_SERVER['who-worker-name-last'];
    $sex      = $_SERVER['who-worker-sex'];
     
    if ($fname != '' && $lname != '')
    {
        echo ("Attn: $fname $lname\n");
        if ($sex == 'F')
            echo ("Dear Ms. $lname,\n");
        else
            echo ("Dear Mr. $lname,\n");
        echo ("Are you still working at \"$biz_name\"?\n");
    }
    ?>
    The rest of the text is static, and will be mailed as "luggage"
    in the body of the letter. You can still of course, embed more
    PHP code <?PHP echo ("like so.\n"); ?>
    

    [3] setting up the recipient list.
    You can manually edit this file by hand or have a program generate it. For the latter, you can use the business textstream class to convert a text file with standard keyword-oriented business listings to the [simplified] databag format required by this object.

    Here is a boilerplate example of a typical listing in a file, in the required databag format:

    # :start-databag:
    target
    (
        id 101175
        full_name Brainbench
        who
        (
            worker
            (
               name ( first Vyacheslav last Molotov )
               sex M
               title "CEO"
            )
        )
        phone <"+1 (703) 674-3500" "+1 (703) 674-3332">
        email <"support@brainbench.com" "marketing@brainbench.com">
        url <"http://www.brainbench.com">
        found "10/23/2013 08:05:37"
    )
    # :end-databag:
    
    Some notes about the formatting rules:
    • By default, each business entry's databag must be preceded with "# :start-databag:" (without the double-quotes, on its own line) and followed by "# :end-databag:" (also on a unique line). . The lines separating
    • the [top-level] name of the databag ("target", in this example) is irrelevant. You can call it whatever you want (but it must have a name).
    • The "id" field is not used. This is an unused extra datum, generated by the business textstream object.
    • The databag name "full_name" is the first item checked in order to obtain the name of the business (/organization). If not present, the object searches for "cased_name", then "short_name". The first non-blank field found is used for naming the organization.
    • The "who" [recursive databag] list can contain multiple "worker" sub-databags. Each entry represents a worker in the organization.
    • Data fields such as phone, url, or found are not used by this class.
    • Data fields such as phone, email, and url are repeatable fields: there can be 0, 1, or more occurances within the angle brackets (which represent an array databag). Since the text representation of each of the aforementioned items contains non-alphanumeric characters (e-mails contain at least a '@' character; phone numbers usually contain '+', '-', or '(' and ')'), the values must be wrapped in double-quotes.
    • In order to send an e-mail to the recipient, obviously at least 1 e-mail address is required.

    [4] make the program.

    [5] run the program.

    Assuming your program is named massmailer.exe and the INI file for it is mail.ini, you can make a command-line processor that searches for the keyword "-ini", like so:

    #include "z_inifile.h"
    inifile_o ini;
     
    int cmdline (const int argc, const char **argv)
    {
        int i;
        string_o s;
        for (i=1; i < argc; i++)
        {
            s = argv[i];
            if (s == "-ini")
                ini.set_name(argv[++i]);
        }
        return 0;
    }
    
    Given such a setup, open a cmd ("console") window and run it:
    massmailer -ini mail.ini
    

    warnings.
    Be very careful about quoting text in the INI file. In the future, given a "key-value" pair (syntax: KEY=VALUE), you will be able to append comments by starting text with a '#' (sharp character) in the 'value part, like so:

    MESSAGE_START=TO BE, OR NOT TO BE? # this is a comment

    However, this will not work:

    MESSAGE_START="TO BE, OR NOT TO BE?" # this is a comment

    That is becuase the INI processor wraps the 'value' part in double-quotes. Internally, when getting the value in the last case (above), it will see this line: ""TO BE, OR NOT TO BE?" # this is a comment"

    It will get the quoted string - which is the stuff in between the first pair of double-quotes that it encounters, which is an empty string - and the remainder of the line will be discarded. However, as of this writing (July 2012), appending comments in this way IS NOT IMPLEMENTED (this entire warning section has been written as a footnote for a future implementation).

    limitations.
    As of this writing, there are some hard-coded protocols you need to know:
    The format of the recipient list has some rather specific rules. It must be in regular text format, and consist of a list of businesses (or other organizations). By default, each biz-org entry starts with this line:

    # :start-databag:
    
    and ends with this line:
    # :end-databag:
    
    You can change the lines of text that act as delimiters for the databags by using the INI parameters (under [run]) BAG_TOPMARKER, BAG_BOTMARKER, and BAG_SEPARATOR. You can use either a separator, or a top and bottom marker pair. For the latter, the databag must be preceded with a top-marker and followed by the bottom marker. Also, the INI parameter BAG_SEPARATOR must be explicitly set to an empty string. For example, if you have these parameters in your INI file:
    BAG_TOPMARKER   = ////---o
    BAG_BOTMARKER   = \\\\---o
    BAG_SEPARATOR   =
    
    The recipient list file should contain entries like so:
    ////---o
    target ( id 100 full_name "Acme Cement Company" )
    \\\\---o
    ////---o
    target
    (
        id 101
        full_name "Another Business Entity"
    )
    ////---o
    
    If, instead the databag separator mode is used, you use a single-line item to separate databags. Given this INI parameter set:
    BAG_TOPMARKER   =
    BAG_BOTMARKER   =
    BAG_SEPARATOR   = [((((NEXT-DATABAG))))]
    
    The recipient list file can look like so:
    target ( id 100 full_name "Acme Cement Company" )
     
    [((((NEXT-DATABAG))))] (...this is the 3rd entry)
     
    target
    (
        id 101
        full_name "Another Business Entity"
    )
     
    [((((NEXT-DATABAG))))]
    target ( id 102 full_name "Etc #3" who (name (first John last Doe )) )
     
    

    Some usage rules for these markers:
    • to use upper- and lower- delimiter pairs, include BAG_SEPARATOR in the INI file, and set it to nothing, ie, "BAG_SEPARATOR =". When this parameter is an empty string, massmail_o will turn to the other delimiters. By default this is set to "#------o" (without the double-quotes). It is an error to have all 3 parameters set. However, if BAG_SEPARATOR is set (to anything non-empty), the other two are ignored.
    • Each marker parameter is expected to be on its own line, and start the line. That is, the marker text should be the only thing on the line (a newline is allowed). However, extraneous text is permitted to follow the marker text (such as can be seen in the 3rd entry in the above example, " (...this is the 3rd entry)").
    • For separators, the lines should be in between the databags. For upper-lower pairs, they should envelop each databag. Thus in the latter case the first line should be the top marker and the last line in the file should be a bottom marker.
    If accessing a database (to record e-mail sends), currently the only method is via ODBC. This maps onto this call:
    zdb_set_access_method(zstyle_DBax_ODBC);

    This should be configurable in the near future.

    Various console messages for emitted for warnings, errors, and checkpoints. These are done at volume levels given by the macro values zMM_Intolerable_Volume, zMM_Volume_FatalErr, and zMM_Volume_BasicMsg. In later versions, these should be under programmatic control in future releases.