File Coverage

blib/lib/Mail/Bulkmail/Dynamic.pm
Criterion Covered Total %
statement 9 205 4.3
branch 0 118 0.0
condition 0 85 0.0
subroutine 3 14 21.4
pod 10 11 90.9
total 22 433 5.0


line stmt bran cond sub pod time code
1             package Mail::Bulkmail::Dynamic;
2              
3             # Copyright and (c) 1999, 2000, 2001, 2002, 2003 James A Thomason III (jim@jimandkoka.com). All rights reserved.
4             # Mail::Bulkmail::Dynamic is distributed under the terms of the Perl Artistic License.
5              
6              
7             =pod
8              
9             =head1 NAME
10              
11             Mail::Bulkmail::Dynamic - platform independent mailing list module for mail merges and dynamically built
12             messages
13              
14             =head1 AUTHOR
15              
16             Jim Thomason, jim@jimandkoka.com
17              
18             =head1 SYNOPSIS
19              
20             my $bulk = Mail::Bulkmail::Dynamic->new(
21             "merge_keys" => [qw(BULK_EMAIL name id address city state zip)],
22             "merge_delimiter" => "::",
23             "LIST" => "~/my.list.txt",
24             "From" => "'Jim Thomason'",
25             "Subject" => "This is a test message",
26             "Message" => "Here is my test message"
27             ) || die Mail::Bulkmail->error();
28              
29             $bulk->bulkmail() || die $bulk->error;
30              
31             Don't forget to set up your conf file!
32              
33             =head1 DESCRIPTION
34              
35             Mail::Bulkmail 1.00 had a thing called "filemapping", it was to allow you to dynamically populate certain variables
36             into your message. Put in people's names, or the like.
37              
38             2.00 renamed "filemapping" to the correct term - "mail merging", and also added in the ability to dynamically
39             create your message, if so desired. So you could very easily send out completely different messages to
40             everyone on your list, if so desired. But 2.00 also added a *lot* of processing overhead, most of which
41             was unfortunately in the form of voodoo. i.e., I seem to recall lots of testing, debugging, etc. until I
42             finally reached a point where the code worked and I sent it off. Not quite sure how it worked, mind you,
43             but happy with the fact that it worked nonetheless.
44              
45             3.00 strips that ability out of Mail::Bulkmail, cleans it up, and places it here. This has a few advantages.
46             For one thing, if you're not doing any mailmerging, then you don't have to worry about any of the overhead
47             of building hashes, doing checks, internally handling things, and so on. There wasn't a tremendous amount
48             of useless work done in that case, but it was enough to be noticed. So now use Mail::Bulkmail if you're
49             not doing mail merges, and Mail::Bulkmail::Dynamic if you are.
50              
51             And the other thing is that the code is cleaned up a B. I actually know and understand how it all works
52             now, and it functions much better than previous versions did. Faster, more efficient, and so on.
53              
54             =cut
55              
56 1     1   2226 use Mail::Bulkmail;
  1         3  
  1         12  
57             @ISA = qw(Mail::Bulkmail);
58              
59             $VERSION = '3.12';
60              
61 1     1   10 use strict;
  1         2  
  1         50  
62 1     1   6 use warnings;
  1         3  
  1         9511  
63              
64             =pod
65              
66             =head1 ATTRIBUTES
67              
68             =over 11
69              
70             =item log_all_data
71              
72             boolean flag, 1/0.
73              
74             Mail::Bulkmail has an easy job logging its list items - they're always guaranteed to be single email
75             addresses. Mail::Bulkmail::Dynamic has a harder time, since it's usually an email address and some other data.
76              
77             'jim@jimandkoka.com::Jim Thomason::24'
78             or
79             ['jim@jimandkoka.com', "Jim Thomason", "24"]
80             or
81             {
82             "BULK_EMAIL" => 'jim@jimandkoka.com',
83             "name" => "Jim Thomason",
84             "age" => "24"
85             }
86              
87             Most of that is obviously not simple scalar data and needs to be logged differently. If log_all_data is
88             set to 0, then only the email address will be logged and everything is fine. However, if log_all_data is
89             1, then a hashref containing all of the data is returned (regardless of the type of data structure you
90             initially handed in). Obviously, you will then need to deal with logging yourself, either by logging to an
91             arrayref or (better) to a function call. Logging to a file with log_all_data set to 1 will just give you
92             a useless list of "HASH(0x7482)" and the like.
93              
94             All pieces may be used simultaneously. So in one mailing, you can use merge_keys, dynamic_message_data,
95             dynamic_header_data, and global_merge.
96              
97             =cut
98              
99             __PACKAGE__->add_attr('log_all_data');
100              
101             =pod
102              
103             =item merge_keys
104              
105             This should be much easier to use and understand than it was in prior versions.
106              
107             Okay, let's start off with the simple case, you have a file that contains a list of email addresses:
108              
109             foo@bar.com
110             bob@hope.com
111             john@junior.com
112              
113             And you set up a list with Mail::Bulkmail to mail to them. Your message is something like this:
114              
115             "Hi there. Things are great in my world, how's yours?"
116              
117             This works fine for a while, people are happy, everything's dandy. But then, you decide that it would
118             be nice to personalize your email messages in some fashion. So you switch to Mail::Bulkmail::Dynamic.
119             You'll need more information in your list of addresses now.
120              
121             foo@bar.com::Mr. Foo
122             me@there.com::Bob Hope
123             john@junior.com::John Jr.
124              
125             And then you'll need to define your merge_keys. merge_keys is an arrayref that defines how the data in your
126             file is structured:
127              
128             merge_keys => [qw(BULK_EMAIL <>)]
129              
130             That tells Mail::Bulkmail::Dynamic that the first item in your list is the email address, and the second
131             one is your name. Please note that the email address B be called "BULK_EMAIL", that's the keyword
132             that the module looks for to find the address to send to. The rest of your keys may be named anything you'd
133             like, but avoid naming keys starting with "BULK_", because those are reserved for my use internally and I
134             may add more special keys like that in the future.
135              
136             (You'll also need to make sure that your merge_delimiter is set to "::", see merge_delimiter, below).
137              
138             Now you can change your message to the following:
139              
140             "Hi there, <>. Things are great in my world, how's yours?"
141              
142             This will send out the messages, respectively:
143              
144             Hi there, Mr. Foo. Things are great in my world, how's yours?
145              
146             Hi there, Bob Hope. Things are great in my world, how's yours?
147              
148             Hi there, John Junior. Things are great in my world, how's yours?
149              
150             And voila. Customization. you may include as much data as you'd like:
151              
152             merge_keys = [qw(<> BULK_EMAIL <> <> <> <>)]
153              
154             #in your list:
155             Jim Thomason::jim@jimandkoka.com::IL::24::Programming Perl::titanium powerbook
156              
157             #and then your message.
158              
159             Dear <>,
160             How've you been? I see that your email address is still BULK_EMAIL.
161             Are you still living in <>? And you're still <>, right?
162              
163             Do you still enjoy <>?
164             Well, email me back a message from your <>.
165              
166             And that's all there is to it. Just be sure to remember that any keys you define will get clobbered *anywhere*
167             in the message.
168              
169             merge_keys => [qw(BULK_EMAIL name)]
170             LIST => [qw(jim@jimandkoka.com::Jim)]
171              
172             "Hi there, name. I've always liked your name."
173              
174             You *probably* want that message to populate as:
175              
176             "Hi there, Jim. I've always liked your name."
177              
178             But it will populate as:
179              
180             "Hi there, Jim. I've always liked your Jim."
181              
182             Which doesn't make sense. So just make sure your keys aren't anywhere else in your message. For example,
183              
184             merge_keys => [qw(BULK_EMAIL )]
185             LIST => [qw(jim@jimandkoka.com::Jim)]
186              
187             "Hi there, . I've always liked your name."
188              
189             Your list data may be a delimited scalar, as we've been using in our examples:
190              
191             jim@jimandkoka.com::Jim::24
192              
193             Or an arrayref:
194              
195             ['jim@jimandkoka.com', 'Jim', '24']
196              
197             In both of those cases, the order of the data is important. Each data element matches up to a particular
198             key. So be sure that your data is actually in the same order as defined in your merge_keys array.
199              
200             Alternatively, you can also just store your data in a hash and pass that in:
201              
202             {
203             'BULK_EMAIL' => 'jim@jimandkoka.com',
204             '' => 'Jim',
205             '' => '24'
206             }
207              
208             This is the one case where your merge_keys values will be ignored, and a mailmerge will be done
209             with the key/value pairs passed in that hashtable.
210              
211             Passing in a hashtable is the fastest in terms of internal processing, but there may be additional
212             work on your end to generate the hash. When reading from a file, you should always use delimited strings
213             (since that's what'd be in your file anyway), but from other sources you can experiment with hashrefs
214             or arrayrefs and see which is faster for your uses.
215              
216             mail merges apply to B message B header information. So it's valid to do:
217              
218             $dynamic->Subject("Hello there, ");
219              
220             And have the mail merge pick that up.
221              
222             Note that the merge will be performed in an arbitrary order, independent of what's specified in
223             merge_keys. So don't expect to have one piece of the merge populate into your message before another one.
224              
225             =cut
226              
227             __PACKAGE__->add_attr('merge_keys');
228              
229             =pod
230              
231             =item merge_delimiter
232              
233             If you're reading in from a file, you can't have arrayrefs, hashrefs, whatever. They don't store nicely
234             in text. So your data will probably be a delimited string. In that case, you need to know the delimiter.
235             Set it with merge_delimiter.
236              
237             #in your list
238             jim@jimandkoka.com::Jim
239              
240             #then
241             $dynamic->merge_delimiter("::");
242              
243             #in your list
244             jim@jimandkoka.com-+-Jim
245              
246             #then
247             $dynamic->merge_delimiter('-+-');
248              
249             #in your list
250             jim@jimandkoka.com,Jim
251              
252             #then
253             $dynamic->merge_delimiter(',');
254              
255             Just be sure that your delimiting string occurs *only* as the delimiter and is never embedded in your data.
256             No escaping of a delimiter is possible.
257              
258             =cut
259              
260             __PACKAGE__->add_attr("merge_delimiter");
261              
262             =pod
263              
264             =item global_merge
265              
266             It can be useful to to do a mail merge with non-address specific data. For example, you may want to
267             put today's date in your subject. But it's silly (if not impossible) to populate that data out to all
268             of your addresses. This is where the global_merge comes in.
269              
270             $dynamic->global_merge(
271             {
272             "" => scalar localtime
273             }
274             );
275              
276             or, at creation:
277              
278             my $dynamic = Mail::Bulkmail::Dynamic->new(
279             "global_merge" => {
280             "" => scalar localtime
281             }
282             );
283              
284             will now change to today's date in your message.
285              
286             "Hello, list member. This is the list for "
287              
288             This is a hash table that populates merge data B individual mail merge items. There is no way
289             to use the same key for both a global_merge and a per-address merge. The global merge will always pick it
290             up and the individual merge will miss it. So, as always, use different keys.
291              
292             =cut
293              
294             __PACKAGE__->add_attr('global_merge');
295              
296             =pod
297              
298             =item dynamic_message_data
299              
300             Mail merges are all well and good, they store unique information about a unique email address. But sometimes
301             you want to group together several users and send them the same information based upon some other criteria.
302             That's where dynamic_message_data comes in handy.
303              
304             This is probably easiest explained via examples. dynamic_message_data is a hashref of hashrefs, such as this:
305              
306             $dynamic->dynamic_message_data(
307             {
308             '' => {
309             'over70' => 'napping',
310             '40-50' => 'amassing wealth',
311             '20-40' => 'working',
312             'under20' => 'playing'
313             },
314             '' => {
315             'hates_animals' => "I see you hate animals.",
316             "likes_animals" => "I see you like animals.",
317             "loves_animals" => "I see you love animals."
318             },
319             '' => {
320             'yes' => 'Hi there, ',
321             'no' => 'Hi there'
322             }
323             }
324             );
325              
326             Now then, your merge keys could be defined as such:
327              
328             ->merge_keys([qw(BULK_EMAIL BULK_DYNAMIC_MESSAGE)]);
329              
330             Your list would be:
331              
332             foo@bar.com::Mr. Foo::23::=20-40;=hates_animals;=yes
333             me@there.com::Bob Hope::78::=over70;=likes_animals;=no
334             john@junior.com::John Jr.::14::=under20;=likes_animals;=yes
335              
336             And finally, your message would be:
337              
338             . Judging by your age, which is , you should enjoy .
339             Oh, and
340              
341             The messages sent out would be, respectively:
342              
343             Hi there, Mr. Foo. Judging by your age, which is 23, you should enjoy working.
344             Oh, and I see you hate animals.
345              
346             Hi there. Judging by your age, which is 78, you should enjoy napping.
347             Oh, and I see you like animals.
348              
349             Hi there, John Jr.. Judging by your age, which is 14, you should enjoy playing.
350             Oh, and I see you like animals.
351              
352             See? easy as pie. Your dynamic message should be specified in your merge_keys as BULK_DYNAMIC_MESSAGE,
353             and should be a delimited string (in this case).
354              
355             agegroup=20-40;=hates_animals;=yes
356              
357             You can specify what delimiters you'd like to use. In this case, your dynamic_message_delimiter is ';',
358             and your dynamic_message_value_delimiter is '='.
359              
360             More clearly, this information translates to the following:
361              
362             => 20-40
363             => hates_animals
364             => yes
365              
366             Please note that angle brackets are not required, they're just useful for clarity in our example.
367             This is also perfectly acceptable:
368              
369             $dynamic->dynamic_message_data(
370             {
371             'agegroup' => {
372             'over70' => 'napping',
373             '40-50' => 'amassing wealth',
374             '20-40' => 'working',
375             'under20' => 'playing'
376             }
377             }
378             );
379              
380             me@there.com::Bob Hope::78::agegroup=over70
381              
382             As long as you use the same keys, you're fine.
383              
384             So you should be able to easily see that we'll look up the message associated with being in the agegroup
385             of 20-40, the animallover that hates_animals, and then personilized with a choice of 'yes'.
386              
387             Dynamic message creation is done before mail merging, so you are more than welcome to put mail merge tokens
388             inside your dynamic message, as we did above with the "" token, which may include the mail
389             merge token of "".
390              
391             Don't use the same tokens for mailmerges and dynamic messages, since the system may get confused.
392              
393             Alternatively, instead of a delimited string, you may pass in an arrayref of strings:
394              
395             [qw(agegroup=20-40 =hates_animals =yes)]
396              
397             or an arrayref of arrayrefs:
398              
399             [[qw(agegroup 20-40)], [qw( hates_animals)], [qw( yes)]]
400              
401             or a hashref:
402              
403             {
404             agegroup => 20-40
405             animallover => hates_animals
406             personilized => yes
407             }
408              
409             Passing in a hashtable is the fastest in terms of internal processing, but there may be additional
410             work on your end to generate the hash. When reading from a file, you should always use delimited strings
411             (since that's what'd be in your file anyway), but from other sources you can experiment with hashrefs
412             or arrayrefs and see which is faster for your uses.
413              
414             dynamic messages apply to B message information. use dynamic_header_data for dynamic pieces in headers.
415              
416             Note that the dynamic message creation will be performed in an arbitrary order. So don't expect to
417             have one piece of the dynamic message populate into your message before another one.
418              
419             There is one special key for dynamic_message_data, "_default".
420              
421             $dynamic->dynamic_message_data(
422             {
423             '' => {
424             'over70' => 'napping',
425             '40-50' => 'amassing wealth',
426             '20-40' => 'working',
427             'under20' => 'playing',
428             '_default' => 'You have not specified an age group'
429             },
430             '' => {
431             'hates_animals' => "I see you hate animals.",
432             "likes_animals" => "I see you like animals.",
433             "loves_animals" => "I see you love animals.",
434             "_default" => "I don't know how you feel about animals"
435             },
436             '' => {
437             'yes' => 'Hi there, ',
438             'no' => 'Hi there',
439             }
440             }
441             );
442              
443             It should be fairly obvious - if that key is not specified, then the _default value is used.
444             Using our earlier example, with the following list:
445              
446             foo@bar.com::Mr. Foo::23::=20-40
447              
448             And the same message of:
449              
450             . Judging by your age, which is , you should enjoy .
451             Oh, and
452              
453             The messages sent out would be, respectively:
454              
455             . Judging by your age, which is 23, you should enjoy working.
456             Oh, and I don't know how you feel about animals.
457              
458             Note that since was specified, we used that value. Since was not specified,
459             the default was used, and since was not specified and has no default, it was simply wiped out.
460              
461              
462             =cut
463              
464             __PACKAGE__->add_attr('dynamic_message_data');
465              
466             =pod
467              
468             =item dynamic_message_delimiter
469              
470             If you're reading in from a file, you can't have arrayrefs, hashrefs, whatever. They don't store nicely
471             in text. So your data will probably be a delimited string. In that case, you need to know the delimiter.
472             Set it with dynamic_message_delimiter. Note that your dynamic message data is just an entry in your
473             merge data. We'll assume a merge_delimiter of '::' and a dynamic_message_value_delimiter of '=' for
474             these examples
475              
476             ->merge_keys([qw(BULK_EMAIL BULK_DYNAMIC_MESSAGE)]);
477              
478             #in your list
479             jim@jimandkoka.com::Jim::agegroup=20-40;animallover=yes
480              
481             #then
482             $dynamic->dynamic_message_delimiter(";");
483              
484             #in your list
485             jim@jimandkoka.com::Jim::agegroup=20-40&animallover=yes
486              
487             #then
488             $dynamic->dynamic_message_delimiter('&');
489              
490             #in your list
491             jim@jimandkoka.com::Jim::agegroup=20-40,,animallover=yes
492              
493             #then
494             $dynamic->dynamic_message_delimiter(',,');
495              
496             Just be sure that your delimiting string occurs *only* as the delimiter and is never embedded in your data.
497             No escaping of a delimiter is possible.
498              
499             =cut
500              
501             __PACKAGE__->add_attr("dynamic_message_delimiter");
502              
503             =pod
504              
505             =item dynamic_message_value_delimiter
506              
507             If you're reading in from a file, you can't have arrayrefs, hashrefs, whatever. They don't store nicely
508             in text. So your data will probably be a delimited string. In that case, you need to know the delimiter.
509             Set it with dynamic_message_delimiter. Note that your dynamic message data is just an entry in your
510             merge data. We'll assume a merge_delimiter of '::' and a dynamic_message_delimiter of ';' for these
511             examples
512              
513             ->merge_keys([qw(BULK_EMAIL BULK_DYNAMIC_MESSAGE)]);
514              
515             #in your list
516             jim@jimandkoka.com::Jim::agegroup=20-40;animallover=yes
517              
518             #then
519             $dynamic->dynamic_message_value_delimiter("=");
520              
521             #in your list
522             jim@jimandkoka.com::Jim::agegroup:=20-40;animallover:=yes
523              
524             #then
525             $dynamic->dynamic_message_value_delimiter(':=');
526              
527             #in your list
528             jim@jimandkoka.com::Jim::agegroup--20-40;animallover--yes
529              
530             #then
531             $dynamic->dynamic_message_value_delimiter('--');
532              
533             Just be sure that your delimiting string occurs *only* as the delimiter and is never embedded in your data.
534             No escaping of a delimiter is possible.
535              
536             =cut
537              
538             __PACKAGE__->add_attr("dynamic_message_value_delimiter");
539              
540              
541             =pod
542              
543             =item dynamic_header_data
544              
545             Mail merges are all well and good, they store unique information about a unique email address. But sometimes
546             you want to group together several users and send them the same information based upon some other criteria.
547             That's where dynamic_message_data comes in handy. dynamic_header_data is virtually identical to dynamic_message_data
548             in terms of behavior, but it operates on the message header instead of the message instelf.
549              
550             This is probably easiest explained via examples. dynamic_header_data is a hashref of hashrefs, such as this:
551              
552             $dynamic->dynamic_header_data(
553             {
554             'Subject' => {
555             'polite' => "Hello, sir",
556             "impolite" => "Hello",
557             "rude" => "Hey, jerk-off"
558             },
559             'Reply-To' => {
560             'useful' => 'return@myaddress.com',
561             'semiuseful' => 'filteredreturn@myaddress.com',
562             'useless' => 'nowhere@noemail.com'
563             },
564             'X-Type' => {
565             'premium' => "All Services are available",
566             "gold" => "Most servies are available",
567             "none" => "No services are available"
568             }
569             }
570             );
571              
572             Now then, your merge keys could be defined as such:
573              
574             ->merge_keys([qw(BULK_EMAIL BULK_DYNAMIC_MESSAGE BULK_DYNAMIC_HEADERS)]);
575              
576             Your list would be:
577              
578             foo@bar.com::Mr. Foo::23::agegroup=20-40;animallover=hates_animals;personalized=yes::Subject=polite;Reply-To:useful;X-Type:gold
579             me@there.com::Bob Hope::78::agegroup=over70;animallover=likes_animals;personalized=no::Subject=rude;Reply-To:useful;X-Type:premium
580             john@junior.com::John Jr.::14::agegroup=under20;animallover=likes_animals;personalized=yes::Subject=impolite;Reply-To:useless;X-Type:none
581              
582             The messages sent out would have the following headers, respectively:
583              
584             Subject : Hello, sir
585             Reply-To: return@myaddress.com
586             X-Type : Most services are available
587              
588             Subject : Hey, jerk-off
589             Reply-To: return@myaddress.com
590             X-Type : All Services are available
591              
592             Subject : Hello
593             Reply-To: nowhere@noemail.com
594             X-Type : No services are available
595              
596              
597             See? easy as pie. Your dynamic headers should be specified in your merge_keys as BULK_DYNAMIC_HEADERS,
598             and should be a delimited string (in this case).
599              
600             Subject=polite;Reply-To=useful;X-Type=gold
601              
602             You can specify what delimiters you'd like to use. In this case, your dynamic_header_delimiter is ';',
603             and your dynamic_header_value_delimiter is '='.
604              
605             More clearly, this information translates to the following:
606              
607             Subject => polite
608             Reply-To => useful
609             X-Type => gold
610              
611             Note that unlike dynamic_message_data, the key in this case is not used to substitute out a string in your
612             headers (or message), the key is used to name the header that is appended on the message.
613              
614             Dynamic header creation is done before mail merging, so you are more than welcome to put mail merge tokens
615             inside your dynamic headers.
616              
617             Don't use the same tokens for mailmerges and dynamic headers, since the system may get confused.
618              
619             Alternatively, instead of a delimited string, you may pass in an arrayref of strings:
620              
621             [qw(Subject=polite Reply-To=useful X-Type:gold)]
622              
623             or an arrayref of arrayrefs:
624              
625             [[qw(Subject polite)], [qw(Reply-To useful)], [qw(X-Type gold)]]
626              
627             or a hashref:
628              
629             {
630             Subject => polite
631             Reply-To => useful
632             X-Type => gold
633             }
634              
635             Passing in a hashtable is the fastest in terms of internal processing, but there may be additional
636             work on your end to generate the hash. When reading from a file, you should always use delimited strings
637             (since that's what'd be in your file anyway), but from other sources you can experiment with hashrefs
638             or arrayrefs and see which is faster for your uses.
639              
640             dynamic headers apply to B header information. use dynamic_message_data for dynamic pieces in messages.
641              
642             Note that the dynamic header creation will be performed in an arbitrary order. So don't expect to
643             have one piece of the dynamic header populate into your message before another one.
644              
645             There is one special key for dynamic_header_data, "_default".
646              
647             $dynamic->dynamic_message_data(
648             {
649             'Subject' => {
650             'polite' => "Hello, sir",
651             "impolite" => "Hello",
652             "rude" => "Hey, jerk-off",
653             '_default' => "Default subject",
654             },
655             'Reply-To' => {
656             'useful' => 'return@myaddress.com',
657             'semiuseful' => 'filteredreturn@myaddress.com',
658             'useless' => 'nowhere@noemail.com',
659             '_default" => 'reply@to.com'
660             },
661             'X-Type' => {
662             'premium' => "All Services are available",
663             "gold" => "Most servies are available",
664             "none" => "No services are available"
665             }
666             }
667             );
668              
669             Behavior is similar to that of _default in dynamic_message_data. If a header is specified, it is used.
670             If no value is specified, it will attempt to use the _default value. But, in this case, if there is no
671             value passed and no default, then the header just won't be set. Unless it is one of the speciality headers,
672             such as From. In that case, it will attempt a specific dynamic_message_data value for From, then the
673             "_default" value in dynamic_message_data for from, and then finally the ->From value itself.
674              
675             If there's a header specified in ->dynamic_header_data, it will be preferred to use over one
676             set via ->header.
677              
678             i.e., the order that a header will be checked is:
679              
680             1) Is there a specific header key for the header? (Subject => polite)
681             2) Is there a default header key for the header? (Subject => _default)
682             3) Is this a specialty header (i.e., ->From), and is that set? ($bulk->From())
683             4) Is there a generic, non-dynamic header set? (->header('Foo'))
684              
685             Headers will not be set more than once, no matter how many places you specify them.
686              
687             =cut
688              
689             __PACKAGE__->add_attr('dynamic_header_data');
690              
691             =pod
692              
693             =item dynamic_header_delimiter
694              
695             If you're reading in from a file, you can't have arrayrefs, hashrefs, whatever. They don't store nicely
696             in text. So your data will probably be a delimited string. In that case, you need to know the delimiter.
697             Set it with dynamic_header_delimiter. Note that your dynamic header data is just an entry in your
698             merge data. We'll assume a merge_delimiter of '::' and a dynamic_header_value_delimiter of '=' for
699             these examples
700              
701             ->merge_keys([qw(BULK_EMAIL BULK_DYNAMIC_HEADERS)]);
702              
703             #in your list
704             jim@jimandkoka.com::Jim::Subject=polite;Reply-To=useful
705              
706             #then
707             $dynamic->dynamic_message_delimiter(";");
708              
709             #in your list
710             jim@jimandkoka.com::Jim::Subject=polite&Reply-To=useful
711              
712             #then
713             $dynamic->dynamic_message_delimiter('&');
714              
715             #in your list
716             jim@jimandkoka.com::Jim::Subject=polite,,Reply-To=useful
717              
718             #then
719             $dynamic->dynamic_message_delimiter(',,');
720              
721             Just be sure that your delimiting string occurs *only* as the delimiter and is never embedded in your data.
722             No escaping of a delimiter is possible.
723              
724             =cut
725              
726             __PACKAGE__->add_attr("dynamic_header_delimiter");
727              
728             =pod
729              
730             =item dynamic_header_value_delimiter
731              
732             If you're reading in from a file, you can't have arrayrefs, hashrefs, whatever. They don't store nicely
733             in text. So your data will probably be a delimited string. In that case, you need to know the delimiter.
734             Set it with dynamic_header_delimiter. Note that your dynamic header data is just an entry in your
735             merge data. We'll assume a merge_delimiter of '::' and a dynamic_header_delimiter of ';' for these
736             examples
737              
738             ->merge_keys([qw(BULK_EMAIL BULK_DYNAMIC_HEADERS)]);
739              
740             #in your list
741             jim@jimandkoka.com::Jim::Subject=polite;Reply-To=useful
742              
743             #then
744             $dynamic->dynamic_message_value_delimiter("=");
745              
746             #in your list
747             jim@jimandkoka.com::Jim::Subject:=polite;Reply-To:=useful
748              
749             #then
750             $dynamic->dynamic_message_value_delimiter(':=');
751              
752             #in your list
753             jim@jimandkoka.com::Jim::Subject--polite;Reply-To--useful
754              
755             #then
756             $dynamic->dynamic_message_value_delimiter('--');
757              
758             Just be sure that your delimiting string occurs *only* as the delimiter and is never embedded in your data.
759             No escaping of a delimiter is possible.
760              
761             =cut
762              
763              
764             __PACKAGE__->add_attr("dynamic_header_value_delimiter");
765              
766             =pod
767              
768             =item quotemeta
769              
770             boolean flag. 1/0
771              
772             While mailmerging, you can specify keys that would contain regex meta data.
773              
774             For example:
775              
776             ->merge_keys [qw(*name* BULK_EMAIL)]
777              
778             Would generate an error, because the * character has special meaning to a regex. With quotemeta turned on,
779             you can use that as a token because it will be quoted when used in the regex.
780              
781             It is B recommended that you leave quotemeta set to 1. Set it to 0 only if you really know what you're doing.
782              
783             =cut
784              
785             __PACKAGE__->add_attr('quotemeta');
786              
787             =pod
788              
789             =item use_envelope
790              
791             In this subclass, use_envelope is a method that will always return 0.
792              
793             For Dynamic messages, it's impossible to use the envelope. Sorry, gang, if you want to
794             use mail merges, then you can't use the added speed that the envelope provides you with.
795              
796             And it only makes sense, because envelope sending sends the exact same message to multiple people.
797             If you're doing a mail merge, then you're customizing each message, so it wouldn't make sense
798             to send that thing to multiple people.
799              
800             For raw speed, use Mail::Bulkmail and use_envelope => 1. For mail merges, use this.
801              
802             =cut
803              
804 0     0 1   sub use_envelope { return 0};
805              
806             =pod
807              
808             =back
809              
810             =head1 METHODS
811              
812             =over 11
813              
814             =item extractEmail
815              
816             extractEmail is an overridden method from Mail::Bulkmail. Most of the time when you're in Mail::Bulkmail::Dynamic,
817             the data structure that's passed around internally is a hashref, and the email address is at the key BULK_EMAIL.
818              
819             This extracts that key and returns it. Again, this method is used internally and is not something you need to worry about.
820              
821             This method is known to be able to return:
822              
823             MBD001 - no BULK_EMAIL defined
824              
825             =cut
826              
827             sub extractEmail {
828              
829 0     0 1   my $self = shift;
830 0           my $data = shift;
831              
832             #if this is a hash, then we'll assume that we want the BULK_EMAIL key out of it.
833 0 0         if (ref $data eq "HASH"){
834              
835             #return the BULK_EMAIL key if we have it, an error otherwise
836 0 0         if ($data->{"BULK_EMAIL"}){
837 0           return $self->valid_email($data->{"BULK_EMAIL"});
838             }
839             else {
840 0           return $self->error("No BULK_EMAIL defined", "MBD001");
841             };
842             }
843             #otherwise, it's assumed to be a single email address, so we just use the super method
844             else {
845 0           return $self->SUPER::extractEmail($data, @_);
846             };
847              
848             };
849              
850             =item extractSender
851              
852             extractSender is an overridden method from Mail::Bulkmail. Most of the time when you're in Mail::Bulkmail::Dynamic,
853             the data structure that's passed around internally is a hashref, and the sender is at the key BULK_SENDER.
854              
855             This extracts that key and returns it. Again, this method is used internally and is not something you need to worry about.
856              
857             This method is known to be able to return:
858              
859             MBD015 - no BULK_SENDER defined
860              
861             =cut
862              
863             sub extractSender {
864              
865 0     0 1   my $self = shift;
866 0           my $data = shift;
867              
868             #if this is a hash, then we'll assume that we want the BULK_SENDER key out of it.
869 0 0         if (ref $data eq "HASH"){
870              
871             #return the BULK_SENDER key if we have it, an error otherwise
872 0 0         if ($data->{"BULK_SENDER"}){
873 0           return $self->valid_email($data->{"BULK_SENDER"});
874             }
875             }
876             #otherwise, it's assumed to be a single email address, so we just use the super method
877 0           return $self->SUPER::extractSender($data, @_);
878              
879             };
880              
881             =item extractReplyTo
882              
883             extractReplyTo is an overridden method from Mail::Bulkmail. Most of the time when you're in Mail::Bulkmail::Dynamic,
884             the data structure that's passed around internally is a hashref, and the email address is at the key BULK_REPLYTO.
885              
886             This extracts that key and returns it. Again, this method is used internally and is not something you need to worry about.
887              
888             This method is known to be able to return:
889              
890             MBD016 - no BULK_REPLYTO defined
891              
892             =cut
893              
894             sub extractReplyTo {
895              
896 0     0 1   my $self = shift;
897 0           my $data = shift;
898              
899             #if this is a hash, then we'll assume that we want the BULK_REPLYTO key out of it.
900 0 0         if (ref $data eq "HASH"){
901              
902             #return the BULK_REPLYTO key if we have it, an error otherwise
903 0 0         if ($data->{"BULK_REPLYTO"}){
904 0           return $self->valid_email($data->{"BULK_REPLYTO"});
905             }
906             }
907             #otherwise, it's assumed to be a single email address, so we just use the super method
908 0           return $self->SUPER::extractReplyTo($data, @_);
909              
910             };
911              
912             =pod
913              
914             =item buildHeaders
915              
916             Another overridden method from Mail::Bulkmail. This one constructs headers and also includes any dynamic headers, if
917             they have been specified in BULK_DYNAMIC_HEADERS.
918              
919             And, finally, it will do a mail merge on all headers (first global, then individual).
920              
921             Still called internally and still something you don't need to worry about.
922              
923             This ->buildHeaders cannot accept the optional second headers_hash parameter
924              
925             This method is known to be able to return:
926              
927             MBD013 - cannot bulkmail w/o From
928             MBD014 - cannot bulkmail w/o To
929              
930             =cut
931              
932             sub buildHeaders {
933 0     0 1   my $self = shift;
934 0           my $data = shift;
935              
936              
937 0           my $headers = undef;
938              
939 0           $headers .= "Date: " . $self->Date . "\015\012";
940              
941             # keep track of the headers that we have set from dynamic_header_data
942 0           my $set = {};
943              
944 0 0 0       if (ref $data eq "HASH" && $data->{"BULK_DYNAMIC_HEADERS"}){
945 0           foreach my $key (keys %{$self->dynamic_header_data}) {
  0            
946              
947 0   0       my $subkey = $data->{"BULK_DYNAMIC_HEADERS"}->{$key} || '_default';
948 0           my $val = $self->dynamic_header_data->{$key}->{$subkey};
949              
950 0 0 0       next if ! defined $val || $val !~ /\S/;
951              
952 0 0         next if $set->{$key}++;
953              
954 0           $headers .= $key . ": " . $val . "\015\012";
955             };
956             };
957              
958             #now, we take care of our regular headers, including the ones that could return errors if not present
959              
960 0 0         unless ($set->{"From"}){
961 0 0         if (my $from = $self->From){
962 0           $headers .= "From: " . $from . "\015\012";
963             }
964             else {
965 0           return $self->error("Cannot bulkmail...no From address", "MBD013");
966             };
967             };
968              
969 0 0 0       $headers .= "Subject: " . $self->Subject . "\015\012" if ! $set->{"Subject"} && defined $self->Subject && $self->Subject =~ /\S/;
      0        
970              
971 0 0         unless ($set->{"To"}){
972 0 0         if (my $to_hash = $self->extractEmail($data)){
973 0           my $to = $to_hash->{'original'};
974 0           $headers .= "To: $to\015\012";
975             }
976             else {
977 0           return $self->error("Cannot bulkmail...no To address", "MBD014");
978             };
979             };
980              
981 0           my $sender_hash = $self->extractSender($data);
982 0 0 0       if (! $set->{"Sender"} && defined $sender_hash) {
983 0           $headers .= "Sender: " . $sender_hash->{'original'} . "\015\012";
984             }
985              
986 0           my $reply_to_hash = $self->extractReplyTo($data);
987 0 0 0       if (! $set->{"ReplyTo"} && defined $reply_to_hash) {
988 0           $headers .= "Reply-To: " . $reply_to_hash->{'original'} . "\015\012";
989             };
990              
991             #we're always going to specify at least a list precedence
992 0 0 0       $headers .= "Precedence: " . ($self->Precedence || 'list') . "\015\012" unless $set->{"Precedence"};
993              
994              
995 0 0         unless ($self->{"Content-type"}){
996 0 0         if ($self->_headers->{"Content-type"}){
997 0           $headers .= "Content-type: " . $self->_headers->{"Content-type"} . "\015\012";
998             }
999             else {
1000 0 0         if ($self->HTML){
1001 0           $headers .= "Content-type: text/html\015\012";
1002             }
1003             else {
1004 0           $headers .= "Content-type: text/plain\015\012";
1005             };
1006             };
1007             };
1008             #done with our default headers
1009              
1010 0           foreach my $key (keys %{$self->_headers}) {
  0            
1011 0 0         next if $key eq 'Content-type';
1012 0           my $val = $self->_headers->{$key};
1013              
1014 0 0 0       next if ! defined $val || $val !~ /\S/;
1015              
1016 0 0         next if $set->{$key}++;
1017              
1018 0           $headers .= $key . ": " . $val . "\015\012";
1019             };
1020              
1021             #do our global value merge
1022 0 0         if ($self->global_merge){
1023              
1024             #iterate through the keys of the global_merge hash, and swap them with the relevant values
1025             #this is part of our mail merge, but not the main customization
1026              
1027 0           foreach my $key (keys %{$self->global_merge}){
  0            
1028 0   0       my $val = $self->global_merge->{$key} || '';
1029 0 0         my $key = $self->quotemeta() ? "\Q$key\E" : $key;
1030 0           $headers =~ s/$key/$val/g;
1031             };
1032             };
1033              
1034             #if we have a mail merge, then do it.
1035 0 0         if (ref $data eq "HASH"){
1036              
1037             #iterate through the keys of the merge_hash, and swap them with the relevant values
1038             #this is our mailmerge
1039 0           foreach my $key (keys %$data){
1040 0 0         next if ref $data->{$key};
1041 0   0       my $val = $data->{$key} || '';
1042 0 0         my $key = $self->quotemeta() ? "\Q$key\E" : $key;
1043 0           $headers =~ s/$key/$val/g;
1044             };
1045             };
1046              
1047             # I'm taking credit for the mailing, dammit!
1048 0           $headers .= "X-Bulkmail: " . $Mail::Bulkmail::Dynamic::VERSION . "\015\012";
1049              
1050 0           $headers = $self->_force_wrap_string($headers, 'start with a blank', 'no blank lines');
1051              
1052 0           $headers .= "\015\012"; #blank line between the header and the message
1053              
1054 0           return \$headers;
1055              
1056             };
1057              
1058             =pod
1059              
1060             =item buildMessage
1061              
1062             Another overridden method from Mail::Bulkmail. This one constructs the message and also includes any dynamic message content,
1063             if it has been specified in BULK_DYNAMIC_MESSAGE.
1064              
1065             And, finally, it will do a mail merge on the message (first global, then individual).
1066              
1067             Still called internally and still something you don't need to worry about.
1068              
1069             This method is known to be able to return:
1070              
1071             MBD012 - cannot build message w/o message
1072              
1073             =cut
1074              
1075             sub buildMessage {
1076 0     0 1   my $self = shift;
1077 0           my $data = shift;
1078              
1079             #Mail::Bulkmail builds the message for us just fine, then we'll do the mail merge into it.
1080 0   0       my $message = $self->Message()
1081             || return $self->error("Cannot build message w/o message", "MBD012");
1082              
1083             #first of all, dynamically build a message, if so desired
1084 0 0 0       if (ref $data eq "HASH" && $data->{"BULK_DYNAMIC_MESSAGE"}){
1085 0           foreach my $key (keys %{$self->dynamic_message_data}) {
  0            
1086              
1087 0   0       my $subkey = $data->{"BULK_DYNAMIC_MESSAGE"}->{$key} || '_default';
1088 0   0       my $val = $self->dynamic_message_data->{$key}->{$subkey} || '';
1089              
1090 0 0         my $key = $self->quotemeta() ? "\Q$key\E" : $key;
1091 0           $message =~ s/$key/$val/g;
1092             };
1093             };
1094              
1095             #do our global value merge
1096 0 0         if ($self->global_merge){
1097              
1098             #iterate through the keys of the global_merge hash, and swap them with the relevant values
1099             #this is part of our mail merge, but not the main customization
1100              
1101 0           foreach my $key (keys %{$self->global_merge}){
  0            
1102 0   0       my $val = $self->global_merge->{$key} || '';
1103 0 0         my $key = $self->quotemeta() ? "\Q$key\E" : $key;
1104 0           $message =~ s/$key/$val/g;
1105             };
1106             };
1107              
1108             #if we have a mail merge, then do it.
1109 0 0 0       if ($self->merge_keys || ref $data eq 'HASH'){
1110              
1111             #iterate through the keys of the merge_hash, and swap them with the relevant values
1112             #this is our mailmerge
1113 0           foreach my $key (keys %$data){
1114 0 0         next if ref $data->{$key};
1115 0   0       my $val = $data->{$key} || '';
1116 0 0         my $key = $self->quotemeta() ? "\Q$key\E" : $key;
1117              
1118 0           $message =~ s/$key/$val/g;
1119             };
1120             };
1121              
1122             #sendmail-ify our line breaks
1123 0           $message =~ s/(?:\r?\n|\r\n?)/\015\012/g;
1124              
1125 0           $message = $self->_force_wrap_string($message);
1126              
1127             #double any periods that start lines
1128 0           $message =~ s/^\./../gm;
1129              
1130             #and force a CRLF at the end, unless one is already present
1131 0 0         $message .= "\015\012" unless $message =~ /\015\012$/;
1132 0           $message .= ".";
1133              
1134 0           return \$message;
1135             };
1136              
1137             =pod
1138              
1139             =item preprocess
1140              
1141             Overridden from Mail::Bulkmail, preprocesses the data returned from getNextLine($bulk->LIST) and makes sure that
1142             Mail::Bulkmail::Dynamic knows how to work with it. Constructs the internal data structures to handle mail merges,
1143             dynamic messages, and dynamic headers, for any of those items that are in use.
1144              
1145             Still called internally and still not something you need to worry about.
1146              
1147             =cut
1148              
1149             sub preprocess {
1150 0     0 1   my $self = shift;
1151 0           my $data = shift;
1152              
1153             #make sure it's a reference
1154 0   0       $data = $self->SUPER::preprocess($data) || return undef;
1155              
1156             #build the mail merge hash, if necessary
1157 0 0         if ($self->merge_keys){
1158 0           my $original = $data;
1159 0   0       $data = $self->buildMergeHash($data) || return undef;
1160 0 0 0       $data->{"BULK_ORIGINAL"} ||= $original if ref $original ne "HASH";
1161             };
1162              
1163             #if we have a dynamic message component, then build the dynamic message data
1164 0 0 0       if (ref $data eq "HASH" && $self->dynamic_message_data){
1165 0   0       $data->{"BULK_DYNAMIC_MESSAGE"} = $self->SUPER::preprocess($data->{"BULK_DYNAMIC_MESSAGE"}) || return undef;
1166 0   0       $data->{"BULK_DYNAMIC_MESSAGE"} = $self->buildDynamicMessageHash($data->{"BULK_DYNAMIC_MESSAGE"}) || return undef;
1167             };
1168              
1169             #if we have a dynamic header component, then build the dynamic header data
1170 0 0 0       if (ref $data eq "HASH" && $self->dynamic_header_data){
1171 0   0       $data->{"BULK_DYNAMIC_HEADERS"} = $self->SUPER::preprocess($data->{"BULK_DYNAMIC_HEADERS"}) || return undef;
1172 0   0       $data->{"BULK_DYNAMIC_HEADERS"} = $self->buildDynamicHeaderHash($data->{"BULK_DYNAMIC_HEADERS"}) || return undef;
1173             };
1174              
1175 0           return $data;
1176              
1177             };
1178              
1179             =pod
1180              
1181             =item buildMessageHash
1182              
1183             Given a delimited string, arrayref, or hashref, formats it according to the information contained in merge_keys and
1184             returns it.
1185              
1186             Called internally, and not something you should worry about.
1187              
1188             This method is known to be able to return:
1189              
1190             MBD002 - no merge_delimiter
1191             MBD003 - different number of keys and values
1192             MBD004 - cannot bulid merge hash
1193              
1194             =cut
1195              
1196             sub buildMergeHash {
1197 0     0 0   my $self = shift;
1198 0           my $data = shift;
1199              
1200             #if it's a hashref, then just return it. We'll use that as the keys AND values and
1201             #completely ignore whatever's in merge_keys
1202             #we're putting this first because it should be the most common case
1203 0 0         if (ref $data eq 'HASH'){
    0          
    0          
1204 0           return $data;
1205             }
1206             # okay, if it's a string, then we want to split it on the merge_delimiter, and use that
1207             # as an array of values with the merge_keys
1208             elsif (ref $data eq "SCALAR"){
1209              
1210 0   0       my $delimiter = quotemeta($self->merge_delimiter())
1211             || return $self->error("Cannot split without a merge_delimiter", "MBD002");
1212 0           my @values = split(/$delimiter/, $$data, scalar @{$self->merge_keys});
  0            
1213              
1214 0           return $self->error("I won't attempt a mail merge unless there are the same number of keys and values", "MBD003")
1215 0 0         unless @values == @{$self->merge_keys};
1216              
1217             #we need to create the hash to return
1218 0           my $mergehash = {};
1219 0           foreach my $key (@{$self->merge_keys}){
  0            
1220 0           $mergehash->{$key} = shift @values;
1221             };
1222              
1223 0           return $mergehash;
1224             }
1225             #arrays behave just like strings, but we don't need to split the string into an arrayref first
1226             elsif (ref $data eq 'ARRAY'){
1227              
1228 0           return $self->error("I won't attempt a mail merge unless there are the same number of keys and values", "MBD003")
1229 0 0         unless @$data == @{$self->merge_keys};
1230              
1231             #we need to create the hash to return
1232 0           my $mergehash = {};
1233              
1234             #I'm not going to shift off of @$data, because I want to leave the arrayref intact, but it'd be
1235             #wasteful to de-reference it here and shift off the copy. So we'll just increment through it
1236 0           my $i = 0;
1237              
1238 0           foreach my $key (@{$self->merge_keys}){
  0            
1239 0           $mergehash->{$key} = $data->[$i++];
1240             };
1241              
1242 0           return $mergehash;
1243             }
1244             #and, finally, if it's none of the above, then we can't deal with it, so return an error.
1245             else {
1246 0           return $self->error("Cannot build merge hash...I don't know what a $data is", "MBD004");
1247             };
1248             };
1249              
1250             =pod
1251              
1252             =item buildDynamicMessageHash
1253              
1254             Given a delimited string, arrayref, or hashref, formats it according to the information contained in dynamic_message_data and
1255             returns it.
1256              
1257             Called internally, and not something you should worry about.
1258              
1259             This method is known to be able to return:
1260              
1261             MBD005 - cannot split w/o dynamic_message_delimiter
1262             MBD006 - cannot split w/o dynamic_message_value_delimiter
1263             MBD007 - invalid dynamic message key
1264             MBD008 - cannot build dynamic message hash
1265              
1266             =cut
1267              
1268             sub buildDynamicMessageHash {
1269 0     0 1   my $self = shift;
1270 0           my $data = shift;
1271              
1272             #if it's a hashref, then just return it, so that's our keys and values
1273             #we're putting this first because it should be the most common case
1274 0 0         if (ref $data eq 'HASH'){
    0          
    0          
1275 0           return $data;
1276             }
1277             # okay, if it's a string, then we want to split it on the merge_delimiter, and use that
1278             # as an array of values with the merge_keys
1279             elsif (ref $data eq "SCALAR"){
1280              
1281 0   0       my $delimiter = quotemeta($self->dynamic_message_delimiter())
1282             || return $self->error("Cannot split without a dynamic_message_delimiter", "MBD005");
1283              
1284 0   0       my $eqdelimiter = quotemeta($self->dynamic_message_value_delimiter())
1285             || return $self->error("Cannot split without a dynamic_message_value_delimiter", "MBD006");
1286              
1287 0           my @values = split(/$delimiter/, $$data);
1288              
1289             #we need to create the hash to return
1290 0           my $dynamicmessagehash = {};
1291              
1292 0           foreach my $pair (@values){
1293 0           my ($key, $value) = split(/$eqdelimiter/, $pair);
1294              
1295 0 0         return $self->error("Invalid dynamic message key : $key", "MBD007")
1296             unless exists $self->dynamic_message_data->{$key};
1297              
1298 0           $dynamicmessagehash->{$key} = $value;
1299             };
1300              
1301 0           return $dynamicmessagehash;
1302             }
1303             #arrays behave just like strings, but we don't need to split the string into an arrayref first
1304             elsif (ref $data eq 'ARRAY'){
1305              
1306             #we need to create the hash to return
1307 0           my $dynamicmessagehash = {};
1308              
1309 0           foreach my $pair (@$data){
1310 0           my ($key, $value);
1311 0 0         if (ref $pair){
1312 0           ($key, $pair) = @$pair;
1313             }
1314             else {
1315 0   0       my $eqdelimiter = quotemeta($self->dynamic_message_value_delimiter())
1316             || return $self->error("Cannot split without a dynamic_message_value_delimiter", "MBD006");
1317 0           ($key, $pair) = split(/$eqdelimiter/, $pair);
1318             };
1319              
1320 0           $dynamicmessagehash->{$key} = $value;
1321             };
1322              
1323 0           return $dynamicmessagehash;
1324             }
1325             #and, finally, if it's none of the above, then we can't deal with it, so return an error.
1326             else {
1327 0           return $self->error("Cannot build dynamic message hash...I don't know what a $data is", "MBD008");
1328             };
1329             };
1330              
1331             =pod
1332              
1333             =item buildDynamicHeaderHash
1334              
1335             Given a delimited string, arrayref, or hashref, formats it according to the information contained in dynamic_header_data and
1336             returns it.
1337              
1338             Called internally, and not something you should worry about.
1339              
1340             This method is known to be able to return:
1341              
1342             MBD008 - cannot split w/o dynamic_header_delimiter
1343             MBD009 - cannot split w/o dynamic_header_value_delimiter
1344             MBD010 - invalid dynamic header key
1345             MBD011 - cannot build dynamic header hash
1346              
1347             =cut
1348              
1349              
1350             sub buildDynamicHeaderHash {
1351 0     0 1   my $self = shift;
1352 0   0       my $data = shift || {};
1353              
1354             #if it's a hashref, then just return it. so that's our keys and values
1355             #we're putting this first because it should be the most common case
1356 0 0         if (ref $data eq 'HASH'){
    0          
    0          
1357 0           return $data;
1358             }
1359             # okay, if it's a string, then we want to split it on the merge_delimiter, and use that
1360             # as an array of values with the merge_keys
1361             elsif (ref $data eq "SCALAR"){
1362              
1363 0   0       my $delimiter = quotemeta($self->dynamic_header_delimiter())
1364             || return $self->error("Cannot split without a dynamic_header_delimiter", "MBD008");
1365              
1366 0   0       my $eqdelimiter = quotemeta($self->dynamic_header_value_delimiter())
1367             || return $self->error("Cannot split without a dynamic_header_value_delimiter", "MBD009");
1368              
1369 0           my @values = split(/$delimiter/, $$data);
1370              
1371             #we need to create the hash to return
1372 0           my $dynamicheaderhash = {};
1373              
1374 0           foreach my $pair (@values){
1375 0           my ($key, $value) = split(/$eqdelimiter/, $pair);
1376              
1377 0 0         return $self->error("Invalid dynamic header key : $key", "MBD010")
1378             unless exists $self->dynamic_header_data->{$key};
1379              
1380 0           $dynamicheaderhash->{$key} = $value;
1381             };
1382              
1383 0           return $dynamicheaderhash;
1384             }
1385             #arrays behave just like strings, but we don't need to split the string into an arrayref first
1386             elsif (ref $data eq 'ARRAY'){
1387              
1388             #we need to create the hash to return
1389 0           my $dynamicheaderhash = {};
1390              
1391 0           foreach my $pair (@$data){
1392 0           my ($key, $value);
1393 0 0         if (ref $pair){
1394 0           ($key, $pair) = @$pair;
1395             }
1396             else {
1397 0   0       my $eqdelimiter = quotemeta($self->dynamic_header_value_delimiter())
1398             || return $self->error("Cannot split without a dynamic_header_value_delimiter", "MBD009");
1399 0           ($key, $pair) = split(/$eqdelimiter/, $pair);
1400             };
1401              
1402 0           $dynamicheaderhash->{$key} = $value;
1403             };
1404              
1405 0           return $dynamicheaderhash;
1406             }
1407             #and, finally, if it's none of the above, then we can't deal with it, so return an error.
1408             else {
1409 0           return $self->error("Cannot build dynamic header hash...I don't know what a $data is", "MBD011");
1410             };
1411             };
1412              
1413              
1414             =pod
1415              
1416             =item convert_to_scalar
1417              
1418             convert_to_scalar is still used exclusively internally here, and you still don't need to worry about it.
1419             The difference is that this time, our data passed in is not just a simple email address - it's a hash.
1420             If log_all_data is set to true, then you get back the data in the form that you had originally passed it,
1421             arrayref, hashref, or delimited string.
1422              
1423             Alternatively, the user can decide to just log the email address, if the dynamic and merge information
1424             are not important.
1425              
1426             =cut
1427              
1428             sub convert_to_scalar {
1429 0     0 1   my $self = shift;
1430 0           my $value = shift;
1431              
1432 0 0         if ($self->log_all_data()){
1433 0 0 0       my $v2 = ref $value eq 'HASH' ? ($value->{"BULK_ORIGINAL"} || $value) : $value;
1434 0 0         return ref $v2 eq "SCALAR" ? $$v2 : $v2;
1435             }
1436             else {
1437 0 0         return ref $value eq 'HASH' ? $value->{"BULK_EMAIL"} : $self->SUPER::convert_to_scalar($value);
1438             };
1439              
1440             };
1441              
1442             1;
1443              
1444             __END__