File Coverage

blib/lib/Mail/Bulkmail.pm
Criterion Covered Total %
statement 243 422 57.5
branch 82 232 35.3
condition 38 160 23.7
subroutine 28 32 87.5
pod 22 22 100.0
total 413 868 47.5


line stmt bran cond sub pod time code
1             package Mail::Bulkmail;
2              
3             # Copyright and (c) 1999, 2000, 2001, 2002, 2003 James A Thomason III (jim@jimandkoka.com). All rights reserved.
4             # Mail::Bulkmail is distributed under the terms of the Perl Artistic License.
5              
6             # Mail::Bulkmail is still my baby and shall be supported forevermore.
7              
8             =pod
9              
10             =head1 NAME
11              
12             Mail::Bulkmail - Platform independent mailing list module
13              
14             =head1 AUTHOR
15              
16             Jim Thomason, jim@jimandkoka.com (http://www.jimandkoka.com)
17              
18             =head1 SYNOPSIS
19              
20             use Mail::Bulkmail /path/to/conf.file
21              
22             my $bulk = Mail::Bulkmail->new(
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 gives a fairly complete set of tools for managing mass-mailing lists. I initially
36             wrote it because the tools I was using at the time were just too damn slow for mailing out to
37             thousands of recipients. I keep working on it because it's reasonably popular and I enjoy it.
38              
39             In a nutshell, it allows you to rapidly transmit a message to a mailing list by zipping out the
40             information to them via an SMTP relay (your own, of course). Subclasses provide the ability to
41             use mail merges, dynamic messages, and anything else you can think of.
42              
43             Mail::Bulkmail 3.00 is a major major B upgrade to the previous version (2.05), which
44             was a major upgrade to the previous version (1.11). My software philosophy is that most code
45             should be scrapped and re-written every 6-8 months or so. 2.05 was released in October of 2000, and
46             I'm writing these docs for 3.00 in January of 2003. So I'm at least 3 major re-writes behind.
47             (philosophy is referenced in the FAQ, below)
48              
49             But that's okay, because we're getting it done now.
50              
51             3.00 is about as backwards compatible to 2.00 as 2.00 is to 1.00. That is to say, sorta. I've
52             tried to make a note of things where they changed, but I'm sure I missed things. Some things can
53             no longer be done, lots are done differently, some are the same. You will need to change your code
54             to update from 1.x or 2.x to 3.00, though. That's a given.
55              
56             So what's new for 3.00? Lots of stuff.
57              
58             Immediate changes are:
59              
60             * code compartmentalization
61             * multi-server support
62             * conf file
63              
64             The immediate change is that the code is now compartmentalized.
65             Mail::Bulkmail now just handles ordinary, non-dynamic mailings. See Mail::Bulkmail::Dynamic for the
66             merging and dynamic text abilities from the prior versions.
67              
68             Server connections are no longer handled directly in Mail::Bulkmail (Smtp attribute, Port attribute,
69             etc.), there is now a separate Mail::Bulkmail::Server object to handle all of that.
70              
71             And everything subclasses off of Mail::Bulkmail::Object, where I have my super-methods to define
72             my objects, some helper stuff, and so on.
73              
74             It's just a lot easier for me to maintain, think about it, etc. if it's all separated. It's also easier
75             for you, the user, if you want to make changes to things. Just subclass it, tweak it, and use it.
76             Very straightforward to modify and extend now. 2.x and below *could* do it, but it wasn't really that
77             easy (unless you were making very trivial changes). This should rectify that.
78              
79             Another major change is the addition of multi-server support. See the docs in Mail::Bulkmail::Server for
80             more information. You can still specify one SMTP relay if that's all you've got, but if you have multiple
81             servers, Mail::Bulkmail can now load balance between them to help take the stress off. No matter what,
82             the biggest bottleneck to all of this is network performance (both to the SMTP relay and then from
83             the relay to the rest of the world), so i wanted to try and help alleviate that by using multiple servers.
84             I know that some people were doing that on there own with small changes, but this allows you to do it all
85             invisibly.
86              
87             And finally, finally, finally there is a conf file. Documentation on the format is in Mail::Bulkmail::Object.
88             It's pretty easy to use. This is the conf file format that I designed for my own use (along with most of the
89             rest of Mail::Bulkmail::Object). The software also has the ability to read multiple conf files, if so
90             desired. So no more worrying about asking your sysadmin to tweak the values in your module somewhere up in /usr/lib/whatever
91              
92             Just have him create the conf file you want, or pass in your own as desired.
93              
94             conf_files are specified and further documented in Mail::Bulkmail::Object, in an internal array called @conf_files, right
95             at the top of the module. To specify a universal conf file, put it in that array (or have your sysadmin do so).
96             Alternatively, you can also add a conf_file via the conf_files accessor.
97              
98             Mail::Bulkmail->conf_files('/path/to/conf_file', '/path/to/other/conf_file'); #, etc.
99              
100             But the recommended way is to specify your conf file upon module import.
101              
102             use Mail::Bulkmail 3.00 "/path/to/conf/file";
103              
104             In addition, there is the usual plethora of bug fixes, tweaks, clean-ups, and so on.
105              
106             And yes, the horrid long-standing bug in the Tz method is B No, honest.
107              
108             I'm also trying a new documentation technique. The pod for a given method is now in the module by that
109             method, as opposed to everything being bunched up at the bottom. Personally, I prefer everything being bunched
110             up there for clarities sake. But from a maintenance point of view, spreading it all out makes my life much easier.
111              
112             =head1 requires
113              
114             Perl 5.6.0, Socket
115             (It probaly can get by with less than 5.6.0, but I haven't tested it in such an environment)
116              
117             =cut
118              
119 1     1   10741 use Mail::Bulkmail::Object;
  1         3  
  1         6  
120             @ISA = Mail::Bulkmail::Object;
121              
122             $VERSION = '3.12';
123              
124 1     1   18 use Socket;
  1         3  
  1         2499  
125              
126 1     1   18 use strict;
  1         2  
  1         812  
127 1     1   10 use warnings;
  1         3  
  1         20438  
128              
129             =head1 ATTRIBUTES
130              
131             =over 11
132              
133             =cut
134              
135             #attributes for storing important headers
136              
137             # you'll note that these 5 attributes are email addresses and don't use the standard add_attr
138             # instead, they're wrapped to call _email_accessor internally instead of _accessor as normal.
139             # Externally, it's the same. $obj->From($value) sets it and $obj->From() reads it
140             #
141             # But this also creates additional internal methods for the slots. So there is a ->From and a ->_From
142             # for example. ->_From internally stores whatever is accepted by ->From, and same with the rest of them.
143             # Don't access the ->_ attributes directly, use the wrappers instead.
144              
145             =pod
146              
147             =item From
148              
149             Stores the From address of this mailing. Must be a valid email address, unless Trusting is set.
150             Really really should be a valid email address anyway.
151              
152             From is no longer used as the Sender, as was the behavior in prior versions. Now, Mail::Bulkmail
153             first tries to use the Sender as the Sender, and failing that, falls back on the from.
154              
155             $bulk->From('"Jim Thomason"');
156             print $bulk->From;
157              
158             =cut
159              
160             __PACKAGE__->add_attr(["From", '_email_accessor'], 0);
161              
162             =pod
163              
164             =item To
165              
166             Stores the To address of this mailing. Must be a valid email address, unless Trusting is set.
167             Really should be a valid email address anyway.
168              
169             To is used if you have use_envelope set to 1. See use_envelope, below. If you are not using the envelope,
170             then the actual email address that we are currently on is used instead and ->To is never used at all.
171              
172             $bulk->To('jimslist:;');
173             print $bulk->To;
174              
175             As of 3.00, ->To may contain either a valid email address or a valid group definition. A group definition is as follows
176             (pseudo-regex):
177              
178             Groupname:(address(,address)*)?;
179              
180             i.e., "the group name", then a colon, then an optional list of email addresses, then a semi-colon
181              
182             $bulk->To('jim@jimandkoka.com');
183             $bulk->To('MyList:jim@jimandkoka.com');
184             $bulk->To('MyList:;');
185              
186             Are all valid addresses. Only the ->To attribute may accept group syntax emails
187              
188             =cut
189              
190             __PACKAGE__->add_attr(["To", '_email_accessor'], 1);
191              
192             =pod
193              
194             =item Sender
195              
196             Stores the Sender address of this mailing. Must be a valid email address, unless Trusting is set.
197             Really really should be a valid email address anyway.
198              
199             Sender is mainly used when speaking SMTP to the server, specifically in the RCPT TO command.
200             The spec defines "Sender" as "he who send the message" (paraphrasing), which may not actually be who
201             the message is from. 2.00 used the From address as the Sender.
202              
203             You should specify this, but if you don't then the From value is assumed to be the sender.
204              
205             $bulk->Sender('jim@jimandkoka.com');
206             print $bulk->Sender;
207              
208             If this value is not set, then Mail::Bulkmail B place a Sender header equal to the From value.
209              
210             Note that the ultimate receiving SMTP server is expected to place a Return-Path header in the message. This
211             Return-Path value will be set to the value of the sender of the message, either ->Sender or ->From. This, in
212             turn, will be the address that bounce backs go to. You should not set a Return-Path header yourself, because bad things
213             will result.
214              
215             =cut
216              
217             __PACKAGE__->add_attr(["Sender", '_email_accessor'], 0);
218              
219             =pod
220              
221             =item ReplyTo
222              
223             Stores the Reply-To address of this mailing. Must be a valid email address, unless Trusting is set.
224             Really really should be a valid email address anyway.
225              
226             Reply-To is used as the address that the user's email client should reply to, if present. If this
227             value is not set, then Mail::Bulkmail B place a Reply-To header equal to the From value.
228              
229             Note that even though the attribute is "ReplyTo", the header set is "Reply-To"
230              
231             $bulk->ReplyTo('jim@jimandkoka.com');
232             print $bulk->ReplyTo;
233              
234             =cut
235              
236             __PACKAGE__->add_attr(["ReplyTo", '_email_accessor'], 0);
237              
238             =pod
239              
240             =item Subject
241              
242             Boring old accessor that stores the subject of the message. It's really recommended that this is
243             set either at your object or in the conf file, otherwise you'll send out a mailing list with no subject
244             which will probably be ignored.
245              
246             $bulk->Subject("This is the list you signed up for");
247             print $bulk->Subject;
248              
249             =cut
250              
251             __PACKAGE__->add_attr("Subject");
252              
253             # internally stores the Precedence of the bulkmail object. Should never be accessed
254             # directly, should always be accessed via the ->Precedence method, which does a validation check
255             __PACKAGE__->add_attr("_Precedence");
256              
257             # internally stores all non-standard (read: "not defined above") headers that the bulkmail object
258             # may have. It's stored as a hashref, and should be accessed via the ->header method.
259             __PACKAGE__->add_attr('_headers');
260              
261             # internally stores the _cached_headers for a given message. This is populated by the
262             # buildHeaders() method during mailing. After the headers have been built once, then
263             # buildHeaders returns the value in _cached_headers instead of constantly rebuilding them.
264             #
265             # _cached_headers is static if using the envelope. If not using the envelope, then the
266             # string ##EMAIL## is populated into the To: header, and buildHeaders swaps that for the
267             # actual individual email addresses
268             __PACKAGE__->add_attr('_cached_headers');
269              
270             #attributes for storing boolean flags
271              
272             =pod
273              
274             =item HTML
275              
276             Boolean flag. 1/0 only.
277              
278             A lot of people, though obviously not you, because you're reading the pod, just couldn't figure out how
279             to send HTML messages. It's easy.
280              
281             $bulk->header("Content-type", "text/html");
282              
283             But it was just too hard for most people. So I added this flag.
284              
285             Here's the order:
286              
287             Check and see if ->header("Content-type") is set, if so then send it.
288             Otherwise, check and see if ->HTML is true, if so, then send a content-type of text/html
289             i.e., an HTML message
290             Otherwise, send a content-type of text/plain
291             i.e., a plaintext message
292              
293             $bulk->HTML(1);
294             print $bulk->HTML();
295              
296             =cut
297              
298             __PACKAGE__->add_attr('HTML');
299              
300             =pod
301              
302             =item use_envelope
303              
304             Boolean flag. 1/0 only.
305              
306             use_envelope was the coolest thing I added to Bulkmail 2.00, and is arguably still the best thing I've got
307             here in terms of raw power in your lists.
308              
309             Basically, it's like lasing a stick of dynamite. Mail::Bulkmail is fast. Mail::Bulkmail with use_envelope
310             is mind-numbingly fast.
311              
312             For the uninformed, an email message contains two parts, the message itself and the envelope. Mail servers only
313             care about the envelope (for the most part), since that's where they find out who the message is to and from, and
314             they don't really need to know anything else.
315              
316             A nifty feature of the envelope is that you can submit multiple addresses within the envelope, and then your
317             mail server will automagically send along the message to everyone contained within the envelope. You end up
318             sending a hell of a lot less data across your connection, your SMTP server has less work to do, and everything
319             ends up working out wonderfully.
320              
321             There are two catches. First of all, with envelope sending turned off, the recipient will have their own email
322             address in the "To" field (To: jim@jimandkoka.com, fer instance). With the envelope on, the recipient will only
323             receive a generic email address ("To: list@myserver.com", fer instance) Most people don't care since that's
324             how most email lists work, but you should be aware of it.
325              
326             Secondly, you B and I mean B sort your list by domain. Envelopes can only be bundled up by domain,
327             so that we send all email to a domain in one burst, all of the email to another domain in the next burst, and so
328             on. So you need to have all of your domains clustered together in your list. If you don't, your list will still
329             go out, but it will be a B slower, since Mail::Bulkmail has a fair amount more processing to do when you send
330             with then envelope. This is normally more than offset by the gains received from sending fewer messages. But with
331             an unsorted list, you never see the big gains and you see a major slow down. Sort your lists.
332              
333             $bulk->use_envelope(0);
334             print $bulk->use_envelope;
335              
336             =cut
337              
338             __PACKAGE__->add_attr('use_envelope');
339              
340             =pod
341              
342             =item force80
343              
344             Boolean flag 1/0
345              
346             RFC 2822 recommends that all messages have no more than 80 characters in a line (78 + CRLF), but doesn't require it. if force80 is 1,
347             then it will force a message to have only 80 characters per line. It will try to insert carriage returns between word boundaries,
348             but if it can't, then it will cut words in half to force the limit.
349              
350             Regardless of force80, be warned that RFC 2822 mandates that messages must have no more than 1000 characters per line (998 + CRLF),
351             and that wrapping will be done no matter what. Again, it will try to wrap at word boundaries, but if it can't, it will cut words
352             in half to force the limit.
353              
354             It is recommended that you just have your message with at most 78 characters + CRLF for happiness' sake, and B at most
355             998 characters + CRLF. You may end up with extra CRLFs in your message that you weren't expecting.
356              
357             If your message is not guaranteed to have only < 78 characters + CRLF per line, then it's recommended to have force80 on for
358             full compatibility. Note that force80 will be overridden by ->Trusting('wrapping');
359              
360             =cut
361              
362             __PACKAGE__->add_attr('force80');
363              
364             # internal flag to let ->bulkmail know if a message is waiting. This is necessary for envelope sending:
365             # when we get a new domain from the getNextLine call on LIST, we need to see if there's a waiting message
366             # first. If there is a waiting message, then we need to finish that one up before we start the next one
367             # for the new domain. _waiting_message stores that value
368             __PACKAGE__->add_attr("_waiting_message");
369              
370             #attributes for storing connection information
371              
372             =pod
373              
374             =item servers
375              
376             arrayref of servers.
377              
378             Okay, this is the first major change between 2.x and 3.x. 2.x had methods to connect to one server (->Smtp, ->Port, etc.).
379             3.x doesn't have those, and the relevent things are now in Mail::Bulkmail::Server, instead it has a list of servers.
380              
381             servers should contain an arrayref of server objects. You can either create them externally yourself and pass them in in an arrayref,
382              
383             $bulk->servers([\$server, \$server2, \$server3]);
384              
385             or you can create them in your conf file. See the Mail::Bulkmail::Object for more info on the format of the conf file, and
386             Mail::Bulkmail::Server for the attributes to specify.
387              
388             servers will automatically be populated with a list of all servers in the server_list in the conf file if you don't specify anything,
389             so you really don't need to worry about it.
390              
391             If you'd rather use a different server_file, then pass the server_file flag to the constructor:
392              
393             $bulk = Mail::Bulkmail->new(
394             'server_file' => '/path/to/server_file'
395             );
396              
397             That will B the server_file in B conf file, so use it with caution.
398              
399             Realistically, though, just let the program populate in the values of the servers you specified in the conf file and don't worry about
400             this.
401              
402             Be warned that servers will be populated by the constructor if you do not populate servers at object creation. You may still
403             change servers later (before you begin mailing), but there is the slight performance hit to initialize all of the server objects
404             and then throw them away. This doesn't affect mailing speed in anyway, it'll just take a little longer to get started than it should.
405              
406             =cut
407              
408             __PACKAGE__->add_attr('servers');
409              
410             # internal flag to let ->bulkmail know the domain of the last email address we looked at when using
411             # the envelope. This is necessary to know when we reach a new domain in the LIST. If we have a new
412             # domain (i.e., the current message's domain is different from _cached_domain), then finish off the
413             # message if we _waiting_message is true and then move on
414             __PACKAGE__->add_attr("_cached_domain");
415              
416             # internally stores which index of the ->servers list we're on used and set by nextServer
417             __PACKAGE__->add_attr("_server_index");
418              
419             #attributes for storing information about the message
420              
421             =pod
422              
423             =item Message
424              
425             This stores the message that you will send out to the recipients of your list.
426              
427             $bulk->Message('Hi there. You're on my mailing list');
428             print $bulk->Message;
429              
430             Don't put any headers in your Message, since they won't be transmitted as headers. Instead they will show up in the body
431             of your message text. Use the ->header method instead for additional headers
432              
433             This mutator is known to be able to return:
434              
435             MB020 - could not open file for message
436             MB021 - could not close file for message
437             MB022 - invalid headers from message
438              
439             =cut
440              
441             # The message is actually stored internally (_Message) and accessed via Message.
442             # That way, if we change the message, we can be sure to wipe out the internal _cached_message as well
443             __PACKAGE__->add_attr('_Message');
444              
445             sub Message {
446 2     2 1 6 my $self = shift;
447 2 100       13 $self->_cached_message(undef) if @_;
448              
449 2         5 my @passed = @_;
450            
451 2         6 my $needs_header_extraction = 0;
452            
453 2 100       7 if (@passed) {
454 1         8 $self->_extracted_headers_from_message(0);
455             };
456              
457 2 50       10 if ($self->message_from_file) {
458              
459 0   0     0 my $file = shift @passed || $self->_message_file;
460              
461 0 0 0     0 if (! defined $self->_message_file_access_time || $file ne $self->_message_file || -M $file < $self->_message_file_access_time) {
      0        
462              
463 0         0 $self->_message_file($file);
464 0         0 $self->_message_file_access_time(-M $file);
465              
466             #theoretically, you could call ->Message with no arguments but with message_from_file turned on
467             #in that case, you may re-read the file if it's been modified since you last looked at it.
468             #We're currently in that case. So we wipe out the previously _cached_message to be safe.
469 0         0 $self->_cached_message(undef);
470              
471 0         0 my $handle = $self->gen_handle;
472              
473 0         0 my $message = undef;
474              
475 0 0       0 open ($handle, $file) || return $self->error("Could not open file for message: $!", "MB020");
476              
477             {
478 0         0 local $/ = undef;
  0         0  
479 0         0 $message = <$handle>;
480             }
481              
482 0 0       0 close ($handle) || return $self->error("Could not close file for message: $!", "MB021");
483              
484 0         0 unshift @passed, $message;
485             };
486             };
487              
488             #first, wipe out any previously set headers_from_message
489 2 100       13 if (defined $self->_previous_headers_from_message) {
490 1         2 foreach my $header (@{$self->_previous_headers_from_message}){
  1         5  
491 0         0 $self->header($header, undef);
492             };
493             };
494              
495             #wipe out the list of previously set headers
496 2         11 $self->_previous_headers_from_message([]);
497              
498             #then, if we're setting new headers, we should set them.
499 2 50 33     9 if ($self->headers_from_message && ! $self->_extracted_headers_from_message) {
500 0         0 $self->_extracted_headers_from_message(1);
501 0   0     0 $passed[0] ||= $self->_Message(); #We'll sometimes call this method after setting the message
502             #sendmail-ify our messages newlines
503 0         0 $passed[0] =~ s/(?:\r?\n|\r\n?)/\015\012/g;
504              
505 0         0 my $header_string = undef;
506              
507             #split out the header string and the message body
508 0         0 ($header_string, $passed[0]) = split(/\015\012\015\012/, $passed[0], 2);
509              
510 0         0 my ($last_header, $last_value) = ();
511 0         0 foreach (split/\015\012/, $header_string){
512 0 0       0 if (/:/){
    0          
513 0 0 0     0 if (defined $last_header && defined $last_value) {
514             #set our header
515 0 0       0 $self->header($last_header, $last_value)
516             || return undef; #bubble up the header error
517              
518             #and wipe out the prior values
519 0         0 $last_header = $last_value = undef;
520             };
521 0         0 ($last_header, $last_value) = split(/:/, $_, 2);
522 0         0 push @{$self->_previous_headers_from_message}, $last_header;
  0         0  
523             }
524             elsif (/^\s+/){
525 0         0 $last_value .= "\015\012$_";
526             }
527             else {
528 0         0 return $self->error("Invalid Headers from Message: line ($_)\n\n-->($header_string)", "MB022");
529             };
530             };
531              
532             #clean up any headers that remain
533 0 0 0     0 if (defined $last_header && defined $last_value) {
534             #set our header
535 0 0       0 $self->header($last_header, $last_value)
536             || return undef; #bubble up the header error
537             };
538             };
539              
540 2         11 return $self->_Message(@passed);
541             };
542              
543             # internal method. Looks to see if a the message is being read from disk. If so, if it
544             # was modified since it was read, then it is not current. Otherwise, it is.
545              
546             sub _current_message {
547 1     1   2 my $self = shift;
548              
549 1 50 0     5 if (
      33        
550             $self->message_from_file
551             && (
552             ! defined $self->_message_file_access_time
553             || -M $self->_message_file < $self->_message_file_access_time
554             )
555             ) {
556 0         0 return 0;
557             }
558             else {
559 1         7 return 1;
560             };
561             };
562              
563             # internally stores the _cached_message for a given message. This is populated by the buildMessage()
564             # method during mailing. After the message has been built once, then buildMessage returns the
565             # value in _cached_message instead of constantly rebuilding it.
566             __PACKAGE__->add_attr('_cached_message');
567              
568             =pod
569              
570             =item message_from_file
571              
572             boolean flag. 1/0 only.
573              
574             message_from_file allows you to load your message in from a file. If message_from_file is
575             set to 1, then the value passed to ->Message() will be assumed to be a path to a file on disk.
576             That file will be openned in read mode (if possible), read in, and stored as your message. Note
577             that your entire message text will be read into memory - no matter how large the message may be.
578              
579             This is simply a shortcut so that you don't have to open and read in the message yourself.
580              
581             B This is a bit picky, to put it mildly. No doubt you've read that the constructor actually
582             is taking in its arguments in an array, not a hash. So they're parsed in order, which means you need
583             pass in message_from_file B Message. i.e., this will work:
584              
585             $bulk = Mail::Bulkmail->new(
586             'message_from_file' => 1,
587             'Message' => '/path/to/message.txt',
588             );
589              
590             But this will not:
591              
592             $bulk = Mail::Bulkmail->new(
593             'Message' => '/path/to/message.txt',
594             'message_from_file' => 1,
595             );
596              
597             Ditto for using the mutators. Turn on the flag, i specify the Message.
598              
599             =cut
600              
601             __PACKAGE__->add_attr('message_from_file');
602              
603             # internal caching attribute to store the message file. This way we will be able to re-open
604             # and re-read the message file if it happened to change.
605              
606             __PACKAGE__->add_attr('_message_file');
607              
608             # internal attribute to store the time the message file was last accessed. This allows the message
609             # file to change and be re-read, though lord knows why you'd want to necessarily do something like
610             # that.
611              
612             __PACKAGE__->add_attr('_message_file_access_time');
613              
614             =pod
615              
616             =item headers_from_message
617              
618             boolean flag. 1/0 only.
619              
620             headers_from_message allows you to specify mail headers inside your message body. You may
621             still specify additional headers in the traditional manner.
622              
623             Note that if you change the value of ->Message (not recommended, but there are times you may
624             want to do so), then any headers that were previously set via headers_from_message will be B.
625              
626             any headers specified in the message will be set when you call ->Message.
627              
628             =cut
629              
630             __PACKAGE__->add_attr('headers_from_message');
631              
632             # internal boolean flag. used to govern whether the headers have already been extracted from
633             # the message
634             __PACKAGE__->add_attr('_extracted_headers_from_message');
635              
636             #internal arrayref containing the headers set the last time ->Message was called.
637              
638             __PACKAGE__->add_attr("_previous_headers_from_message");
639              
640             # internal hashref that stores the list of duplicate email addresses populated by setDuplicate and
641             # read by isDuplicate. WARNING - there is a *severe* penalty for using duplicates, this hash can
642             # get really really huge. It is recommended you remove duplicates in advance and turn on
643             # allow_duplicates to prevent this from being populated, if you do use it, then it
644             # is *strongly* recommended that you leave Trusting('banned') off, i.e. Trusting('banned' => 0)
645             __PACKAGE__->add_attr('_duplicates');
646              
647             # internal hashref that stores the list of banned email addresses or domains populated by a call
648             # to banned (which does some magic with _file_accessor). accessed via isBanned
649             # It is *strongly* recommended that you leave Trusting('banned') off, i.e. Trusting('banned' => 0)
650             __PACKAGE__->add_attr('_banned');
651              
652             #attributes for storing filehandles
653              
654             =pod
655              
656             =item LIST
657              
658             LIST stores the list of addresses you're going to mail out to. LIST may be either a coderef, globref, arrayref, or string literal.
659              
660             If a string literal, then Mail::Bulkmail will attempt to open that file as your list:
661              
662             $bulk->LIST("/path/to/my/list");
663              
664             If a globref, it is assumed to be an open filehandle:
665              
666             open (L, "/path/to/my/list");
667             $bulk->LIST(\*L);
668              
669             if a coderef, it is assumed to be a function to return your list, or undef when it is done:
670              
671             sub L {return $listquery->execute()}; #or whatever your code is
672             $bulk->LIST(\&L);
673              
674             The coderef will receive the bulkmail object itself as an argument.
675              
676             if an arrayref, it is assumed to be an array containing your list:
677              
678             my $list = [qw(jim@jimandkoka.com thomasoniii@yahoo.com)];
679             $bulk->LIST($list);
680              
681             Use whichever item is most convenient, and Mail::Bulkmail will take it from there.
682              
683             =cut
684              
685             __PACKAGE__->add_attr(['LIST', '_file_accessor'], '<');
686              
687             =pod
688              
689             =item BAD
690              
691             This is an optional log file to keep track of the bad addresses you have, i.e. banned, invalid, or duplicates.
692              
693             BAD may be either a coderef, globref, arrayref, or string literal.
694              
695             If a string literal, then Mail::Bulkmail will attempt to open that file (in append mode) as your log:
696              
697             $bulk->BAD("/path/to/my/bad.addresses");
698              
699             If a globref, it is assumed to be an open filehandle in append mode:
700              
701             open (B, ">>/path/to/my/bad.addresses");
702             $bulk->BAD(\*L);
703              
704             if a coderef, it is assumed to be a function to call with the address as an argument:
705              
706             sub B { print "BAD ADDRESS : ", $_[1], "\n"}; #or whatever your code is
707             $bulk->BAD(\&B);
708              
709             The coderef will receive two arguments. The first is the bulkmail object itself, and the second
710             is the data in the form that it was returned from the LIST attribute.
711              
712             if an arrayref, then bad addresses will be pushed on to the end of it
713              
714             $bulk->BAD(\@bad);
715              
716             Use whichever item is most convenient, and Mail::Bulkmail will take it from there.
717              
718             =cut
719              
720             __PACKAGE__->add_attr(['BAD', '_file_accessor'], '>>');
721              
722             =pod
723              
724             =item GOOD
725              
726             This is an optional log file to keep track of the good addresses you have, i.e. the ones that
727             Mail::Bulkmail could successfully transmit to the server. Note that there is no guarantee that
728             an email address in the GOOD file actually received your mailing - it could have failed at a
729             later point when out of Mail::Bulkmail's control.
730              
731             GOOD may be either a coderef, globref, arrayref, or string literal.
732              
733             If a string literal, then Mail::Bulkmail will attempt to open that file (in append mode) as your log:
734              
735             $bulk->GOOD("/path/to/my/good.addresses");
736              
737             If a globref, it is assumed to be an open filehandle in append mode:
738              
739             open (B, ">>/path/to/my/good.addresses");
740             $bulk->GOOD(\*B);
741              
742             if a coderef, it is assumed to be a function to call with the address as an argument:
743              
744             sub G { print "GOOD ADDRESS : ", $_[1], "\n"}; #or whatever your code is
745             $bulk->GOOD(\&G);
746              
747             The coderef will receive two arguments. The first is the bulkmail object itself, and the second
748             is the data in the form that it was returned from the LIST attribute.
749              
750             if an arrayref, then bad addresses will be pushed on to the end of it
751              
752             $bulk->GOOD(\@good);
753              
754             Use whichever item is most convenient, and Mail::Bulkmail will take it from there.
755              
756             Please note that ->GOOD only says that the address was initially accepted for delivery. It could later fail while transmitting
757             the email address, or it could be an valid but non-existent address that bounces later. It is up to the end user to inspect your
758             error logs to make sure no errors occurred, and look for (and weed out) bounces or other failures later.
759              
760             =cut
761              
762             __PACKAGE__->add_attr(['GOOD', '_file_accessor'], '>>');
763              
764             #class attributes
765              
766             =pod
767              
768             =item server_class
769              
770             server_class is a class method that B be specified in the conf file. You can initialize it in your program if you
771             really want, but it is B recommended to be in the conf file so you don't forget it.
772              
773             server_class is used by the constructor to create the server list to populate into ->servers, ->servers is not
774             populated in the constructor.
775              
776             By default, this should probably be Mail::Bulkmail::Server, to allow mailing. Another useful value is Mail::Bulkmail::Dummy
777             See Mail::Bulkmail::Server and Mail::Bulkmail::Dummy for more information on how to create those objects.
778              
779             Also, if you write your own server implementation, this would be where you'd hook it into Mail::Bulkmail
780              
781             =cut
782              
783             __PACKAGE__->add_class_attr('server_class');
784              
785             #speciality accessors
786              
787             # _Trusting stores the hashref that is accessed internally by the Trusting method
788              
789             __PACKAGE__->add_attr('_Trusting');
790              
791             =pod
792              
793             =item Trusting
794              
795             Trusting specifies your Trusting level. Mail::Bulkmail 3.00 will do its best to make sure that your email addresses
796             are valid and that your message conforms to RFC 2822. But, there is a slight performance hit to doing that - it does have
797             to check things, do regexes, and so on. It's not very slow, but extrapolated over a huge list, it can be noticeable.
798              
799             So that's where Trusting comes in to play. If you set a Trusting value, then certain tests will be skipped. B
800             own risk>. If you tell Mail::Bulkmail to be Trusting, then it won't verify addresses or to make sure your list is under 1,000
801             characters per line. So if you're Trusting and you pass in bad data, it's your funeral. If there is B chance of invalid data,
802             then don't be Trusting. If you're *positive* there's nothing wrong, then you may be Trusting.
803              
804             Trusting values are set one as key/value pairs.
805              
806             $bulk->Trusting("email" => 1);
807             $bulk->Trusting("wrapping" => 1);
808             $bulk->Trusting("default" => 1);
809              
810             And read back with just the key:
811              
812             $bulk->Trusting("email");
813             $bulk->Trusting("wrapping");
814             $bulk->Trusting("default");
815              
816             default is used as a fall back. So if you didn't specify a Trusting value for "email", for example, it will use
817             the "default" value. Note that the default is only used if a value is not specified.
818              
819             $bulk->Trusting("default" => 1);
820             print $bulk->Trusting("email"); #prints 1
821             print $bulk->Trusting("default"); #prints 1
822             $bulk->Trusting("default" => 0);
823             print $bulk->Trusting("email"); #prints 0
824             print $bulk->Trusting("default"); #prints 0
825             $bulk->Trusting("email" => 1);
826             print $bulk->Trusting("email"); #prints 1
827             print $bulk->Trusting("default"); #prints 0
828             $bulk->Trusting("email" => 0);
829             $bulk->Trusting("default" => 0);
830             print $bulk->Trusting("email"); #prints 0
831             print $bulk->Trusting("default"); #prints 1
832              
833             You may also directly set all values with the integer short cut.
834              
835             $bulk->Trusting(1); # everything is Trusting
836             $bulk->Trusting(0); # nothing is Trusting
837              
838             If you want to specify Trusting in the conf file, you may only directly specify via the integer shortcut. Otherwise, you must
839             use the list equation.
840              
841             # all Trusting
842             Trusting = 1
843              
844             #none Trusting
845             Trusting = 0
846              
847             #email is trusting
848             Trusting @= email
849             Trusting @= wrapping
850              
851             This will not work:
852              
853             Trusting = email
854              
855             If you use that syntax, it will internally do:
856              
857             $bulk->Trusting('email');
858              
859             which you know will only read the value, not set it. If you use the array syntax, it will properly set the value.
860              
861             Note that ->Trusting('default' => 0) is not equivalent to ->Trusting(0). Consider:
862              
863             $bulk->Trusting('email' => 1);
864             print $bulk->Trusting('email'); # prints 1
865             $bulk->Trusting("default' => 0);
866             print $bulk->Trusting('email'); # still prints 1
867             $bulk->Trusting(0);
868             print $bulk->Trusting('email'); # now prints 0
869              
870             Currently, you may set:
871              
872             email - Trusting('email' => 1) will not check for valid email addresses
873             wrapping - Trusting('wrapping' => 1) will not try to wrap the message to reach the 1,000 character per line limit
874             duplicates - Trusting('duplicates' => 1) will not do any duplicates checking
875             (this is the equivalent of allow_duplicates in older versions)
876             banned - Trusting('banned' => 1) will not lowercase the local part of a domain in a banned or duplicates check
877             (this is the opposite of safe_banned in older versions. i.e. $bulk2_05->safe_banned(1) == $bulk_300->Trusting('banned' => 0);
878              
879             It is recommended your conf file be:
880              
881             Trusting @= duplicates
882              
883             Since you're usually better off weeding duplicates out in advance. All other Trusting values are recommended to be false.
884              
885             =cut
886              
887             sub Trusting {
888 23     23 1 29 my $self = shift;
889 23         31 my $key = shift;
890              
891 23 100       57 $self->_Trusting({}) unless $self->_Trusting;
892              
893 23 50       51 if (defined $key) {
894 23 50       97 if (ref $key eq "ARRAY"){
    50          
    50          
895 0         0 foreach my $k (@$key){
896 0         0 $self->_Trusting->{$k} = 1;
897             };
898 0         0 return 1;
899             }
900             elsif (@_){
901 0         0 my $val = shift;
902 0         0 $self->_Trusting->{$key} = $val;
903 0         0 return $val;
904             }
905             elsif ($key =~ /^[10]$/){
906 0         0 $self->_Trusting({});
907 0         0 $self->_Trusting->{'default'} = $key;
908 0         0 return $key;
909             }
910             else {
911 23 50 50     60 return defined $self->_Trusting->{$key}
912             ? $self->_Trusting->{$key}
913             : ($self->_Trusting->{'default'} || 0)
914             };
915             }
916             else {
917 0   0     0 return $self->_Trusting->{'default'} || 0;
918             };
919             };
920              
921             =pod
922              
923             =item banned
924              
925             banned stores the list of email addresses and domains that are banned. Only store user@domain.com portions of
926             email addresses, don't try to ban "Jim", for instance. Only ban jim@jimandkoka.com
927              
928             banned may be either a coderef, globref, arrayref, or string literal.
929              
930             If a string literal, then Mail::Bulkmail will attempt to open that file (in append mode) as your log:
931              
932             $bulk->banned("/path/to/my/banned.addresses");
933              
934             If a globref, it is assumed to be an open filehandle in append mode:
935              
936             open (B, ">>/path/to/my/banned.addresses");
937             $bulk->banned(\*B);
938              
939             files should contain one entry per line, each entry being an email address or a domain. For example:
940              
941             jim@jimandkoka.com
942             jimandkoka.com
943             foo@bar.com
944             bar.com
945              
946             if a coderef, it is assumed to be a function to return your banned list:
947              
948             sub B {return $bannedquery->execute()}; #or whatever your code is
949             $bulk->banned(\&B);
950              
951             The function should return one entry per execution, either an address or a domain.
952              
953             if an arrayref, then it's an array of banned addresses and domains
954              
955             $bulk->banned([qw(jim@jimandkoka.com jimandkoka.com)]);
956              
957             The arrayref can contain email addresses and domains.
958              
959             Use whichever item is most convenient, and Mail::Bulkmail will take it from there.
960              
961             Once banned has been populated, the values are stored internally in a hashref.
962              
963             =cut
964              
965             sub banned {
966 8     8 1 10 my $self = shift;
967              
968 8 50       15 if (@_) {
969 0         0 my $banned = shift;
970              
971             #we're gonna cheat and populate the data into ->_banned via the _file_accessor.
972             #then we'll iterate through it all, pop it into a hash, and then drop
973             #that back into _banned instead
974              
975 0         0 my $ob = $self->_banned(); #save it for below.
976 0         0 $self->_file_accessor("_banned", "<", $banned);
977              
978 0   0     0 my $b = $ob || {}; #keep the old value, or make a new hashref
979              
980 0         0 while (my $address = $self->getNextLine($self->_banned)){
981 0         0 $b->{$address} = 1;
982             };
983              
984 0         0 return $self->_banned($b);
985             }
986             else {
987             #if we have a banned hash, return it.
988 8 100       22 if ($self->_banned){
989 7         22 return $self->_banned;
990             }
991             #otherwise, create one and return that.
992             else {
993 1         4 return $self->_banned({});
994             };
995             };
996             };
997              
998             =pod
999              
1000             =item Precedence
1001              
1002             Precedence is a validating accessor to validate the Precedence you have passed for your mailing list.
1003              
1004             Precedence must be either:
1005              
1006             * list (default) - a mailing list
1007             * bulk - bulk mailing of some type
1008             * junk - worthless test message.
1009              
1010             You can use an alternate Precedence if you set Trusting to 0. But seriously, there's *no* reason to do that. Keeping
1011             the appropriate precedence will help the servers on the internet route your message as well as the rest of the email out
1012             there more efficiently. So don't be a jerk, and leave it as one of those three.
1013              
1014             This method is known to be able to return:
1015              
1016             MB001 - invalid precedence
1017              
1018             =cut
1019              
1020             sub Precedence {
1021 1     1 1 2 my $self = shift;
1022 1         3 my $prop = '_Precedence';
1023              
1024 1 50       6 if (@_){
1025 0         0 my $precedence = shift;
1026 0 0 0     0 if ($self->Trusting('precedence') || $self->_valid_precedence($precedence)){
1027 0         0 $self->_Precedence($precedence);
1028 0         0 return $self->_Precedence;
1029             }
1030             else {
1031 0         0 return $self->error("Invalid precedence: $precedence", "MB001");
1032             };
1033             }
1034             else {
1035 1   50     5 return $self->_Precedence || 'list'; #if they didn't set it, assume list, no matter what
1036             };
1037             };
1038              
1039             #date and tz are actually methods, not accessors, but they're close enough, so what the hell
1040              
1041             =pod
1042              
1043             =item Tz
1044              
1045             Returns the timezone that you're in. You cannot set this value. You'll also never need to worry about it.
1046              
1047             =cut
1048              
1049             sub Tz {
1050              
1051 1     1 1 4 my $self = shift;
1052 1   33     133 my $time = shift || time;
1053              
1054 1         25 my ($min, $hour, $isdst) = (localtime($time))[1,2,-1];
1055 1         7 my ($gmin, $ghour, $gsdst) = (gmtime($time))[1,2, -1];
1056              
1057 1         4 my $diffhour = $hour - $ghour;
1058 1 50       4 $diffhour = $diffhour - 24 if $diffhour > 12;
1059 1 50       4 $diffhour = $diffhour + 24 if $diffhour < -12;
1060              
1061 1         10 ($diffhour = sprintf("%03d", $diffhour)) =~ s/^0/\+/;
1062              
1063 1         14 return $diffhour . sprintf("%02d", $min - $gmin);
1064              
1065             };
1066              
1067             =pod
1068              
1069             =item Date
1070              
1071             Returns the date that this email is being sent, in valid RFC format. Note that this will be stored in _cached_headers as the
1072             date that the first email is sent.
1073              
1074             Another thing you won't need to worry about.
1075              
1076             =cut
1077              
1078             sub Date {
1079              
1080 1     1 1 3 my $self = shift;
1081              
1082 1         10 my @months = qw(Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec);
1083 1         4 my @days = qw(Sun Mon Tue Wed Thu Fri Sat);
1084              
1085 1         10 my $time = time;
1086 1         37 my ($sec, $min, $hour, $mday, $mon, $year, $wday) = localtime($time);
1087              
1088 1         9 return sprintf("%s, %02d %s %04d %02d:%02d:%02d %05s",
1089             $days[$wday], $mday, $months[$mon], $year + 1900, $hour, $min, $sec, $self->Tz($time));
1090             };
1091              
1092             #done with speciality accessors
1093              
1094             #our generic speciality accessors
1095              
1096             # internally used to populate the attributes that are expected to contain email addresses
1097             # basically, it just does a valid_email check on the email address before allowing it into
1098             # the object's attribute. The validation check will be bypassed if Trusting is set
1099             #
1100             # otherwise, the attribute externally behaves just as any other
1101             sub _email_accessor {
1102 10     10   18 my $self = shift;
1103 10         17 my $prop = shift;
1104 10         13 my $allow_groups = shift;
1105              
1106 10 100       23 if (@_){
1107 1         2 my $email = shift;
1108 1 50 33     8 if (! defined $email || $self->Trusting('email') || $self->valid_email($email, $allow_groups)){
      33        
1109 1         11 my $return = $self->$prop($email);;
1110 1 50       9 return defined $email ? $return : 0;
1111             }
1112             else {
1113 0         0 return $self->error("Invalid address: $email", "MB002");
1114             };
1115             }
1116             else {
1117 9         37 return $self->$prop();
1118             };
1119             };
1120              
1121             #done with generic specialty accessors
1122              
1123             #constructor
1124              
1125             =pod
1126              
1127             =back
1128              
1129             =head1 METHODS
1130              
1131             =over 11
1132              
1133             =item new
1134              
1135             The constructor, used to create new Mail::Bulkmail objects. See Mail::Bulkmail::Object for more information on constructors.
1136              
1137             In a nutshell, the constructor accepts a hash with name/value pairs corresponding to attributes and attribute values.
1138              
1139             So that:
1140              
1141             my $bulk = Mail::Bulkmail->new(
1142             'LIST' => './list.txt',
1143             'Message' => "This is my message!",
1144             'HTML' => 0
1145             ) || die Mail::Bulkmail->error;
1146              
1147             is the same as:
1148              
1149             my $bulk = Mail::Bulkmail->new() || die Mail::Bulkmail->error;
1150              
1151             $bulk->LIST("./list.txt");
1152             $bulk->Message("This is my message!");
1153             $bulk->HTML(0);
1154              
1155             *technically* it's not exactly the same, since the constructor will fail with an error if your attribute calls return undef, but
1156             it's close enough.
1157              
1158             It is recommend to tack on an || die after your new() calls, to make sure you're alerted if your object isn't created.
1159              
1160             my $bulk = Mail::Bulkmail->new() || die Mail::Bulkmail->error();
1161              
1162             Otherwise, you won't be alerted if your object isn't created.
1163              
1164             Upon creation, Mail::Bulkmail will first iterate through the conf file and populate all of the attributes defined in the conf file
1165             into your object. It will then iterate through the values you passed to the constructor and mutate the attributes to those
1166             values. If you don't pass any arguments to the constructor, it still gets the default values in the conf file. Values passed to
1167             the constructor always override values specified in the conf file
1168              
1169             There is one special constructor flag, "server_file", which does not correspond to an attribute or method. "server_file" is used to
1170             override the server_file specified in the conf file.
1171              
1172             If you pass a key/value pair to the constructor that doesn't have a corresponding attribute, then it is assuming you are setting a
1173             new header.
1174              
1175             my $bulk = Mail::Bulkmail->new('foo' => 'bar');
1176              
1177             is the same as:
1178              
1179             my $bulk = Mail::Bulkmail->new();
1180             $bulk->header('foo' => 'bar');
1181              
1182             This method is known to be able to return:
1183              
1184             MB003 - could not use server class
1185              
1186             =cut
1187              
1188             sub new {
1189 1     1 1 83 my $class = shift;
1190              
1191 1         10 my %init = @_;
1192              
1193 1   50     24 my $self = $class->SUPER::new(
1194             'servers' => [],
1195             '_headers' => {},
1196             "_duplicates" => {},
1197             "_waiting_message" => 0,
1198             "_server_index" => -1,
1199             @_
1200             ) || return undef;
1201              
1202             #now, we iterate through everything else that was passed, since we're gonna assume
1203             #that they want to set it as a header
1204 1         10 foreach my $key (grep {! $self->can($_)} keys %init){
  7         29  
1205 0 0       0 next if $key eq 'server_file'; #special case to allow passing of a separate server_file
1206 0 0       0 $self->header($key, $init{$key}) || return $class->error($self->error, $self->errcode, 'not logged');
1207             };
1208              
1209             #if we have no servers, but we do have a server file (which we should...)
1210 1 50       34 if ($class->server_class) {
1211 0         0 $@ = undef;
1212 0         0 eval "use " . $class->server_class;
1213 0 0       0 return $self->error("Could not use " . $class->server_class . " : $@", "MB003") if $@;
1214             #if we have no servers, then initialize them via create_all_servers
1215 0         0 $self->servers($class->server_class->create_all_servers($init{'server_file'} || undef))
1216 0 0 0     0 if $class->server_class && @{$self->servers} == 0;
      0        
1217             };
1218              
1219 1         8 return $self;
1220              
1221             };
1222              
1223             =pod
1224              
1225             =item header
1226              
1227             the header method is used to set additional headers for your object that don't have their own methods (such as Subject)
1228             header expects the header and value to act as a mutator, or the header to act as an accessor.
1229              
1230             $bulk->header('X-Header', "My header value");
1231             print $bulk->header('X-Header'); #prints "My header value"
1232              
1233             Use this to set any additional headers that you would like.
1234              
1235             Note that you can't use this to bypass validation checks.
1236              
1237             $bulk->Header("Subject", "My Subject") will internally change into $bulk->Subject("My Subject");
1238              
1239             There's no benefit to doing that, it'll just slow you down.
1240              
1241             If you call header with no values, it returns the _headers hashref, containing key value pairs of header => value
1242              
1243             This method is known to be able to return:
1244              
1245             MB004 - cannot set CC or BCC header
1246             MB005 - invalid header
1247              
1248             =cut
1249              
1250             #header allows us to specify additional headers
1251             sub header {
1252              
1253 0     0 1 0 my $self = shift;
1254 0   0     0 my $header = shift || return $self->_headers;
1255              
1256 0 0       0 if ($header =~ /^(?:From|To|Sender|Reply-?To|Subject|Precedence)$/){
    0          
1257 0         0 $header =~ s/\W//g;
1258 0         0 return $self->$header(@_);
1259             }
1260             elsif ($header =~ /^b?cc/i){
1261 0         0 return $self->error("Cannot set CC or BCC...that's just common sense!", "MB004");
1262             }
1263             else {
1264 0 0       0 if ($header =~ /^[\x21-\x39\x3B-\x7E]+$/){
1265 0         0 my $value = shift;
1266 0 0       0 if (defined $value) {
1267 0         0 $self->_headers->{$header} = $value;
1268 0         0 return $value;
1269             }
1270             else {
1271 0         0 delete $self->_headers->{$header};
1272 0         0 return 0; #non-true value (didn't set it to anything), but a defined value since it's not an error.
1273             };
1274             }
1275             else {
1276 0         0 return $self->error("Cannot set header '$header' : invalid. Headers cannot contain non-printables, spaces, or colons", "MB005");
1277             };
1278             };
1279              
1280             };
1281              
1282             #validation methods
1283              
1284             {
1285             # Mail::Bulkmail 3.00 has a greatly extended routine for validating email addresses. The one in 2.x was pretty good,
1286             # but was only slightly superior to the one in 1.x. It also wasn't quite perfect - there were valid addresses it would
1287             # refuse, and invalid addresses it would accept. It was *mostly* fine, though.
1288             #
1289             # 3.00 has a higher standard, though. :)
1290             # So valid_email has been re-written. This should match only valid RFC 2822 addresses, with deviations from the
1291             # spec noted below. Still only allows single addresses, though. No address lists or groups for the general case.
1292              
1293             # our regexes to deal with whitespace and folding whitespace
1294             my $wsp = q<[ \t]>;
1295             my $fws = qq<(?:(?:$wsp*\\015\\012)?$wsp+)>;
1296              
1297             # our regexes for control characters
1298             my $no_ws_ctl = q<\x01-\x08\x0B\x0C\x0E-\x1F\x7F>;
1299              
1300             # regex for "text", any ascii character other than a CR or LF
1301             my $text = q<[\x01-\x09\x0B\x0C\x14-\x7F]>;
1302              
1303             #regexes for "atoms"
1304              
1305             #define our atomtext
1306             my $atext = q<[!#$%&'*+\-/=?^`{|}~\w]>;
1307              
1308             # an atom is atext optionally surrounded by folded white space
1309             my $atom = qq<(?:$fws*$atext+$fws*)>;
1310              
1311             # a dotatom is atom text optionally followed by a dot and more atomtext
1312             my $dotatomtext = qq<(?:$atext+(?:\\.$atext+)*)>;
1313              
1314             #a dotatom is dotatomtext optionally surrounded by folded whitespace
1315             my $dotatom = qq<(?:$fws?$dotatomtext$fws?)>;
1316              
1317             #a quoted pair is a backslash followed by a single text character, as defined above.
1318             my $quoted_pair = '(?:' . q<\\> . qq<$text> . ')';
1319              
1320             #regexes for quoted strings
1321              
1322             #quoted text is text between quotes, it can be any control character,
1323             #in addition to any ASCII character other than \ or "
1324             my $qtext = '(?:' . '[' . $no_ws_ctl . q<\x21\x23-\x5B\x5D-\x7E> . ']' . ')';
1325              
1326             #content inside a quoted string may either be qtext or a quoted pair
1327             my $qcontent = qq<(?:$qtext|$quoted_pair)>;
1328              
1329             #and, finally, our quoted string is optional folded white space, then a double quote
1330             #with as much qcontent as we'd like (optionally surrounded by folding white space
1331             #then another double quote, and more optional folded white space
1332             my $quoted_string = qq<(?:$fws?"(?:$fws?$qcontent)*$fws?"$fws?)>;
1333              
1334             #a word is an atom or a quoted string
1335             my $word = qq<(?:$atom|$quoted_string)>;
1336              
1337             #a phrase is multiple words
1338             my $phrase = qq<$word+>;
1339              
1340             #the local part of an address is either a dotatom or a quoted string
1341             my $local_part = qq<(?:$dotatom|$quoted_string)>;
1342              
1343             #regexes for domains
1344              
1345             # #domain text may be a control character, in addition to any ASCII character other than [, \, or ]
1346             # my $dtext = '(?:' . '[' . $no_ws_ctl . q<\x21-\x5A\x5E-\x7E> . ']' . ')';
1347             #
1348             # #domain content is either dtext or a quoted pair
1349             # my $dcontent = qq<(?:$dtext|$quoted_pair)>;
1350             #
1351             # #a domain literal is optional folded white space, followed by a literal [
1352             # #then optional folded white space and arbitrary dcontent, followed by another literal ]
1353             # #and then optional fws
1354             # my $domain_literal = qq<(?:$fws?\\[(?:$fws?$dcontent)*\\]$fws)>;
1355             #
1356             # #and, finally, a domain is either a dotatom or a domainliteral.
1357             # my $domain = qq<(?:$dotatom|$domain_literal)>;
1358              
1359             # RFC 2821 is a bit stricter than RFC 2822. In fact, according to that document, a domain may be only
1360             # letters, numbers, and hyphens. Go figure. I kept the old domain specification in the comments
1361             # immediately above here, just 'cuz I was so proud of 'em. :)
1362             my $domain = q<[a-zA-Z0-9\-]+(?:\.[a-zA-Z0-9\-]+)*\\.(?:[a-zA-Z][a-zA-Z](?:[a-zA-Z](?:[a-zA-Z](?:[a-zA-Z][a-zA-Z])?)?)?)>;
1363              
1364             #our address spec. Defines user@domain.com
1365             #note - very important, that the addr_spec is within backtracking parentheses. This value will
1366             #go into either $1 (common) or $2 (not quite as common).
1367             #also note that we deviate from RFC 2822 here, by forcing the TLD of 2,3,4 or 6 characters.
1368             #that's what the internet uses, regardless of what the spec allows.
1369             my $addr_spec = '(' . $local_part . '@' . $domain . ')';
1370              
1371             #a display name (displayname) is just a phrase
1372             my $display_name = $phrase;
1373              
1374             #an angle_addr is just an addr_spec surrounded by < and >, with optional folded white space
1375             #around that
1376             my $angle_addr = qq[(?:$fws?<$addr_spec>$fws?)];
1377              
1378             #a name address is an optional display_name followed by an angle_addr
1379             my $name_addr = qq<(?:$display_name?$angle_addr)>;
1380              
1381             # and a mailbox is either an addr_spec or a name_addr
1382             # the mailbox is our final regex that we use in valid_email
1383             #
1384             my $mailbox = qq<(?:$addr_spec|$name_addr)>;
1385             #
1386             ##
1387              
1388             # a mailbox list is, as it sounds, a list of at least one mailbox, with as many as you'd like, comma delimited
1389             my $mailbox_list = qq<(?:$mailbox(?:,$mailbox)*)>;
1390              
1391             # and a group is a display_name, a :, and an optional mailbox list, ended with a semi-colon
1392             # This is used in the To accessor, which is allowed to contain groups.
1393             my $group = qq<(?:$display_name:(?:$mailbox_list|$fws)?;)>;
1394              
1395             =pod
1396              
1397             =item valid_email
1398              
1399             valid_email validates an email address and extracts the user@domain.com part of an address
1400              
1401             print $bulk->valid_email('jim@jimandkoka.com')->{'extracted'}; #prints jim@jimandkoka.com
1402             print $bulk->valid_email('"Jim Thomason"')->{'extracted'}; #prints jim@jimandkoka.com
1403             print $bulk->valid_email('jim@jimandkoka.com')->{'extracted'}; #prints jim@jimandkoka.com
1404             print $bulk->valid_email('jim@@jimandkoka.com'); #prints nothing (invalid address)
1405              
1406             Note that as of v3.10, valid_email returns a hash with two keys upon success. 'original' contains the address as you
1407             passed it in, 'extracted' is the address person that was yanked out.
1408              
1409             {
1410             'original' => 'Jim Thomason'
1411             'extracted' => 'jim@jimandkoka.com',
1412             }
1413              
1414             Given an invalid address, returns undef and sets an error as always.
1415              
1416             If Trusting is 1, then valid_email only removes comments and extracts the address spec part of the email. i.e., if your address is
1417              
1418             some name
1419              
1420             It'll just return some@address.com. This is required, because valid_email is also where the address spec is validated.
1421             As of 3.00, valid_email should be fully RFC 2822 compliant, except where otherwise noted (such as forcing a valid domain as per RFC 2821).
1422             And also as of 3.00, Trusting is even more trusting and has a faster return. There are speed reasons to have Trusting set
1423             to 1 (such as not having to check the validity of each email address), but if you do that then you must be B that
1424             B of your addresses are 100% valid. If you have B addresses in your list that are invalid and Trusting is set to 1,
1425             then you may have bad things happen. You have been warned.
1426              
1427             This method is known to be able to return:
1428              
1429             MB006 - no email address
1430             MB007 - invalid email address
1431              
1432             =cut
1433              
1434             sub valid_email {
1435              
1436 8     8 1 20 my $self = shift;
1437 8         9 my $email = shift;
1438 8         8 my $allow_groups = shift;
1439              
1440 8         21 my $return_hash = {
1441             'original' => $email
1442             };
1443              
1444 8 50       18 return $self->error("Cannot validate w/o email address", "MB006") unless $email;
1445              
1446 8         23 $email = $self->_comment_killer($email); #No one else handles comments, to my knowledge. Cool, huh? :)
1447              
1448             # if we're trusting, trivially extract the address-spec and return it
1449 8 50       24 if ($self->Trusting('email')){
1450 0         0 $email =~ s/.+<(.+)>/$1/g;
1451 0         0 $return_hash->{'extracted'} = $email;
1452 0         0 return $return_hash;
1453             };
1454              
1455             #okay, check our email address
1456 8 100 33     3267 if ($email =~ m!^$mailbox$!o){
    50          
1457 7   33     83 $return_hash->{'extracted'} = $1 || $2; #our address could be in either place;
1458 7         74 return $return_hash;
1459             }
1460             #if it fails as an email address and we allow groups, see if we were passed a group
1461             elsif ($allow_groups && $email =~ m!^$group$!o){
1462             #the $group regex can't extract emails, so we'll just return the whole thing.
1463 0         0 $return_hash->{'extracted'} = $email;
1464 0         0 return $return_hash;
1465             }
1466             #finally, otherwise give an error
1467             else {
1468 1         5 $self->logToFile($self->BAD, \$email);
1469 1         9 return $self->error("Invalid email address : $email", "MB007");
1470             };
1471             };
1472              
1473             # _comment_killer is used internally by valid_email, _comment_killer does what you'd expect from it, it removes
1474             # comments from email addresses
1475              
1476             sub _comment_killer {
1477              
1478 8     8   28 my $self = shift;
1479 8         9 my $email = shift;
1480              
1481             #comment text is anything in ASCII, except for \, (, and )
1482 8         22 my $ctext = '(' . '[' . $no_ws_ctl . q<\x21-\x27\x2A-\x5B\x5D-\x7E> . ']' . ')';
1483              
1484             #the content of a comment is either ctext or a quoted pair
1485             #we are deviating from RFC 2822, because comments can nest arbitrarily. But we don't allow that.
1486 8         23 my $ccontent = qq<($ctext|$quoted_pair)>; #|$comment, but we don't allow nesting here
1487              
1488             #and finally, a comment is a ( followed by arbitrary ccontent, followed by another )
1489 8         28 my $comment = '(' . '\(' . qq<($fws?$ccontent)*$fws?> . '\)' . ')';
1490              
1491 8         113 while ($email =~ /$comment/o){$email =~ s/$comment//go};
  0         0  
1492              
1493 8         19 return $email;
1494             };
1495              
1496             };
1497              
1498             # _valid_precedence is used internally to check whether a precedence is valid, i.e., list, bulk, or junk
1499             # It is called by the Precedence wrapper to the _Precedence attribute
1500              
1501             sub _valid_precedence {
1502 0     0   0 my $self = shift;
1503 0         0 my $value = shift;
1504              
1505 0 0 0     0 if ($self->Trusting('precedence') || (defined $value && $value =~ /list|bulk|junk/i)){
      0        
1506 0         0 return 1;
1507             } else {
1508 0 0       0 $value = '' unless defined $value;
1509 0         0 return $self->error("Invalid precedence ($value) : only 'list', 'bulk', or 'junk'", "MB008");
1510             };
1511             };
1512              
1513             #/validation
1514              
1515             #now, for the methods
1516              
1517             =pod
1518              
1519             =item lc_domain
1520              
1521             given an email address, lowercases the domain. Mainly used internally, but I thought it might be useful externally as well.
1522              
1523             print $self->lc_domain('Jim@JimANDKoka.com'); #prints Jim@jimandkoka.com
1524             print $self->lc_domain('JIM@JIMANDKOKA.com'); #prints JIM@jimandkoka.com
1525             print $self->lc_domain('jim@jimandkoka.com'); #prints jim@jimandkoka.com
1526              
1527             This method is known to be able to return:
1528              
1529             MB009 - cannot lowercase domain w/o email
1530              
1531             =cut
1532              
1533             sub lc_domain {
1534              
1535             #lowercase the domain part, but _not_ the local part. Why not?
1536             #Read the specs, you can't make assumptions about the local part, it is case sensitive
1537             #even though 99.999% of the net treats it as insensitive.
1538              
1539 0     0 1 0 my $self = shift;
1540              
1541 0   0     0 my $email = shift || return $self->error("Cannot lowercase domain with no email address", "MB009");
1542              
1543 0         0 (my $lc = $email) =~ s/^(.+)@(.+)$/$1@\L$2/;
1544              
1545 0         0 return $lc;
1546              
1547             };
1548              
1549             =pod
1550              
1551             =item setDuplicate
1552              
1553             sets an email address as a duplicate.
1554              
1555             $bulk->setDuplicate($email);
1556              
1557             once an address is set as a duplicate, then isDuplicate will return a true value for that address
1558              
1559             print $bulk->isDuplicate($email2); #prints 0
1560             $bulk->setDuplicate($email2);
1561             print $bulk->isDuplicate($email2); #prints 1
1562              
1563             This is mainly used internally, but I decided to make it external anyway.
1564              
1565             setDuplicate will always return 1 if you have Trusting('duplicates') set.
1566              
1567             Be warned that there is a performance hit to using this, since it will eventually store your entire list inside an
1568             entire hashref in memory. You're in much better shape if you weed out the duplicates in advance and then set Trusting('duplicates' => 1)
1569             to skip the check and skip storing the values in the hashref.
1570              
1571             But if you have to use this to weed out values, go to town.
1572              
1573             This method is known to be able to return:
1574              
1575             MB010 - cannot set duplicate w/o email
1576             =cut
1577              
1578             sub setDuplicate {
1579 2     2 1 5 my $self = shift;
1580 2   50     8 my $email = shift || return $self->error("Cannot set duplicate without email", "MB010");
1581              
1582 2 50       9 return 1 if $self->Trusting('duplicates');
1583              
1584 2 50       8 if (! $self->Trusting('banned')) {
1585 2         36 $self->_duplicates->{lc $email} = 1;
1586             }
1587             else {
1588 0         0 $self->_duplicates->{$self->lc_domain($email)} = 1;
1589             };
1590              
1591 2         7 return 1;
1592             };
1593              
1594             =pod
1595              
1596             =item isDuplicate
1597              
1598             returns a boolean value as to whether an email address is a duplicate
1599              
1600             print $bulk->isDuplicate($email); #prints 0 or 1
1601              
1602             once an address is set as a duplicate, then isDuplicate will return a true value for that address
1603              
1604             print $bulk->isDuplicate($email2); #prints 0
1605             $bulk->setDuplicate($email2);
1606             print $bulk->isDuplicate($email2); #prints 1
1607              
1608             This is mainly used internally, but I decided to make it external anyway.
1609              
1610             isDuplicate will always return 0 if you have Trusting('duplicates' => 1) set.
1611              
1612             Be warned that there is a performance hit to using this, since it will eventually store your entire list inside an
1613             entire hashref in memory. You're in much better shape if you weed out the duplicates in advance and then set Trusting('duplicates' => 1)
1614             to skip the check and skip storing the values in the hashref.
1615              
1616             But if you have to use this to weed out values, go to town.
1617              
1618             =cut
1619              
1620             sub isDuplicate {
1621 2     2 1 4 my $self = shift;
1622 2   50     73 my $email = shift || return $self->undef("Cannot check duplicate without email", "MB015");
1623              
1624 2 50       6 return 0 if $self->Trusting('duplicates');
1625              
1626 2 50       7 if (! $self->Trusting('banned')){
1627 2         10 return $self->_duplicates->{lc $email};
1628             }
1629             else {
1630 0         0 return $self->_duplicates->{$self->lc_domain($email)};
1631             };
1632             };
1633              
1634             =pod
1635              
1636             =item isBanned
1637              
1638             returns a boolean value as to whether an email address (or domain) is banned or not
1639              
1640             $bulk->isBanned($email); #prints 0 or 1
1641             $bulk->isBanned($domain); #prints 0 or 1
1642              
1643             ->isBanned goes off of the values populated via the banned attribute
1644              
1645             This is mainly used internally, but I decided to make it external anyway.
1646              
1647             =cut
1648              
1649             sub isBanned {
1650 4     4 1 6 my $self = shift;
1651 4   50     10 my $email = shift || return $self->undef("Cannot check banned-ness without email", "MB016");
1652              
1653 4         25 (my $domain = $email) =~ s/^.+@//;
1654              
1655 4 50       13 return 2 if $self->banned->{lc $domain};
1656              
1657 4 50       11 if (! $self->Trusting('banned')){
1658 4         9 return $self->banned->{lc $email};
1659             }
1660             else {
1661 0         0 return $self->banned->{$self->lc_domain($email)};
1662             };
1663             };
1664              
1665             =pod
1666              
1667             =item nextServer
1668              
1669             Again, mainly used internally.
1670              
1671             ->nextServer will iterate over the ->servers array and return the next valid, connected server. If a server is
1672             not connected, ->nextServer will try to make it connect. If the server cannot connect, it will go on to the next one.
1673              
1674             Once all servers are exhausted, it returns undef.
1675              
1676             nextServer is called if the present server object has reached one of its internal limits. See Mail::Bulkmail::Server for more
1677             information on server limits.
1678              
1679             This method is known to be able to return:
1680              
1681             MB011 - No servers (->servers array is empty)
1682             MB012 - No available servers (cannot connect to any servers)
1683              
1684             =cut
1685              
1686             sub nextServer {
1687 1     1 1 3 my $self = shift;
1688              
1689 1 50 33     6 return $self->error("No servers", "MB011") unless $self->servers && @{$self->servers};
  1         4  
1690              
1691 1         6 my $old_idx = $self->_server_index;
1692 1         3 my $new_idx = ($old_idx + 1) % @{$self->servers};
  1         5  
1693              
1694             #special case for loop prevention. Internally, we initially start @ -1, to start off at 0 instead of 1.
1695 1 50       5 $old_idx = 0 if $new_idx == 0;
1696              
1697 1         2 while (1){
1698             #prevent infinite loops. If we get back to the beginning AND that server is worthless ("not not worthless"), then
1699             #we can't connect to any of 'em.
1700 1 50 33     10 if ($new_idx == $old_idx && ! $self->servers->[$new_idx]->_not_worthless){
1701 0         0 return $self->error("No available servers", "MB012");
1702             }
1703             else {
1704             #if we're connected, we're golden.
1705 1 50       5 if ($self->servers->[$new_idx]->connected){
1706 0         0 $self->_server_index($new_idx);
1707 0         0 return $self->servers->[$new_idx];
1708             }
1709             #otherwise, try to connect
1710             else {
1711 1         4 $self->servers->[$new_idx]->connect;
1712              
1713             #if we succeed, we're golden
1714 1 50       6 if ($self->servers->[$new_idx]->connected){
1715 1         4 $self->_server_index($new_idx);
1716 1         4 return $self->servers->[$new_idx];
1717             }
1718             }
1719             };
1720              
1721             #otherwise, no matter what, if we're down here we want to look at the next server in the list
1722 0         0 $new_idx = ($new_idx + 1) % @{$self->servers};
  0         0  
1723             };
1724              
1725             };
1726              
1727             =pod
1728              
1729             =item extractEmail
1730              
1731             The extract methods return results equivalent to the return of valid_email
1732              
1733             extracts the email address from the data passed in the bulkmail object. Not necessary in Mail::Bulkmail, since all it
1734             does in here is reflect through the same value that is passed.
1735              
1736             This will be very important in a subclass, though. getNextLine might return values beyond just simple email addresses
1737             in subclasses, hashes, objects, whatever. You name it. In that case, extractEmail is necessary to find the actual email
1738             address out of whatever it is that was returned from getNextLine().
1739              
1740             But here? Nothing to worry about.
1741              
1742             This method is known to be able to return:
1743              
1744             MB013 - cannot extract email w/o email
1745              
1746             =cut
1747              
1748             sub extractEmail {
1749 7     7 1 13 my $self = shift;
1750 7   50     18 my $email = shift || return $self->error("Cannot extract email w/o email", "MB013");
1751              
1752 7         19 return $self->valid_email($$email);
1753              
1754             };
1755              
1756             =pod
1757              
1758             =item extractSender
1759              
1760             The extract methods return results equivalent to the return of valid_email
1761              
1762             extracts the sender of the message from the data passed in the bulkmail object. Not necessary in Mail::Bulkmail, since
1763             all it does in here is return either the Bulkmail object's Sender or its From field.
1764              
1765             This will be very important in a subclass, though. getNextLine might return values beyond just simple email addresses
1766             in subclasses - hashes, object, whatever. You name it. In that case, extractEmail is necessary to find the actual email
1767             address out of whatever it is that was returned from getNextLine().
1768              
1769             But here? Nothing to worry about.
1770              
1771             =cut
1772              
1773             sub extractSender {
1774 3     3 1 6 my $self = shift;
1775              
1776             #we cheat like a madman in this method. We -know- that the Sender and the From are valid, since we validated
1777             #them before they're insered. So we do the trivial extract and return that way.
1778              
1779 3   33     13 my $sender = $self->Sender || $self->From;
1780 3         11 my $return_hash = {'original' => $sender};
1781 3         8 $sender =~ s/.+<(.+)>/$1/g;
1782 3         7 $return_hash->{'extracted'} = $sender;
1783 3         10 return $return_hash;
1784             };
1785              
1786             =pod
1787              
1788             =item extractReplyTo
1789              
1790             The extract methods return results equivalent to the return of valid_email
1791              
1792             extracts the Reply-To of the message from the data passed in the bulkmail object. Not necessary in Mail::Bulkmail, since
1793             all it does in here is return either the Bulkmail object's Sender or its From field.
1794              
1795             This will be very important in a subclass, though. getNextLine might return values beyond just simple email addresses
1796             in subclasses - hashes, object, whatever. You name it. In that case, extractEmail is necessary to find the actual email
1797             address out of whatever it is that was returned from getNextLine().
1798              
1799             But here? Nothing to worry about.
1800              
1801             =cut
1802              
1803             sub extractReplyTo {
1804 1     1 1 2 my $self = shift;
1805              
1806             #we cheat like a madman in this method. We -know- that the Sender and the From are valid, since we validated
1807             #them before they're insered. So we do the trivial extract and return that way.
1808              
1809 1   33     5 my $replyto = $self->ReplyTo || $self->From;
1810 1         4 my $return_hash = {'original' => $replyto};
1811 1         3 $replyto =~ s/.+<(.+)>/$1/g;
1812 1         2 $return_hash->{'extracted'} = $replyto;
1813 1         3 return $return_hash;
1814             };
1815              
1816             =pod
1817              
1818             =item preprocess
1819              
1820             This is another method that'll do more in a subclass. When you had off data to either ->mail or ->bulkmail,
1821             it gets preprocessed before it's actually used. In Mail::Bulkmail itself, all it does is take a non-reference
1822             value and turn it into a reference, or return a reference as is if that was passed.
1823              
1824             Here, the whole method:
1825              
1826             sub preprocess {
1827             my $self = shift;
1828             my $val = shift;
1829              
1830             return ref $val ? $val : \$val;
1831             };
1832              
1833             But in a subclass, this may be much more important. Making sure that your data is uniform or valid, that
1834             particular values are populated, additional tests, whatever.
1835              
1836             =cut
1837              
1838             sub preprocess {
1839 5     5 1 8 my $self = shift;
1840 5         10 my $val = shift;
1841              
1842 5 100       25 return ref $val ? $val : \$val;
1843             };
1844              
1845             # _force_wrap_string is an internal method that handles wrapping lines as appropriate, either to 80 characters per line
1846             # if ->force80 is true, and otherwise to 1000 characters to comply with RFC2822. Will not touch the string
1847             # if Trusting is set to 1.
1848             #
1849             # though this is re-written, I'm still not terribly thrilled with it.
1850              
1851             sub _force_wrap_string {
1852 2     2   4 my $self = shift;
1853 2         3 my $string = shift;
1854 2   100     11 my $spaceprepend= shift || 0;
1855 2   100     9 my $noblanks = shift || 0;
1856              
1857             #if we're trusting the wrap, just return the string
1858 2 50       7 return $string if $self->Trusting('wrapping');
1859              
1860             #determine the length we wrap to
1861 2 50       10 my $length = $self->force80 ? 78 : 998;
1862              
1863             #if we're tacking a space on to the front, that's an extra character, so decrement the length to match
1864 2 100       7 $length-- if $spaceprepend;
1865              
1866             #we want to split into as many fields as there are returns in the message
1867 2         17 my @returns = $string =~ m/(\015\012)/g;
1868              
1869 2         14 my @lines = split(/\015\012/, $string, scalar @returns);
1870 2         5 foreach (@lines){
1871 10 50       22 if (length $_ > $length){
1872 0         0 my $one = 0;
1873             # boy, did this take finesse. Only prepend a space if it's not the start of the original line
1874             # That way, we can properly wrap our headers. That's what $one is.
1875              
1876             # this regex puts as many characters before a wordbreak as it can into $1, and the rest into $2.
1877             # if a string is a solid word greater than the the length, it all goes into $2
1878 0 0 0     0 $_ =~ s/(?:([^\015\012]{1,$length})\b)?([^\015\012]+)/$self->_process_string($1, $2, $length, $spaceprepend && ! $one++ ? 1 : 0)/ge;
  0         0  
1879             };
1880             };
1881              
1882             #rebuild our string
1883 2         8 $string = join("\015\012", @lines);
1884              
1885             #get rid of any blank lines we may have created, if so desired.
1886 2 100       7 if ($noblanks){
1887 1         10 $string =~ s/\015\012[^\015\012\S]*\015\012/\015\012/g while $string =~ /\015\012[^\015\012\S]+\015\012/;
1888             };
1889              
1890 2         8 return $string;
1891             };
1892              
1893             # process string is used internally by _force_wrap_string to do wrapping, as appropriate.
1894              
1895             sub _process_string {
1896 0     0   0 my $self = shift;
1897 0   0     0 my $one = shift || ''; #$1, passed from _force_wrap_string
1898 0   0     0 my $two = shift || ''; #$2, passed from _force_wrap_string
1899 0         0 my $length = shift; #the length we're wrapping to
1900 0   0     0 my $spaceprepend = shift || 0; #whether we're prepending a space
1901              
1902             #re-define the spaceprepend to the character we will prepend.
1903 0 0       0 $spaceprepend = $spaceprepend ? ' ' : '';
1904              
1905             #if we don't have $1, then we have a single word greater than the length. Cut it up at the length point, globally
1906 0 0       0 if (! $one){
1907 0         0 $two =~ s/([^\015\012]{$length})/$1\015\012$spaceprepend/g;
1908 0         0 return $two;
1909             }
1910             #otherwise, use the same regex that _force_wrap_string uses and proceed recusively.
1911             else {
1912 0         0 $two =~ s/(?:([^\015\012]{1,$length})\b)?([^\015\012]+)/$self->_process_string($1, $2, $length, $spaceprepend)/ge;
  0         0  
1913 0         0 return "$one\015\012$spaceprepend$two";
1914             }
1915             };
1916              
1917             =pod
1918              
1919             =item buildHeaders
1920              
1921             buildHeaders is mainly used internally, like its name implies, it builds the headers for the message.
1922              
1923             You'll never need to call buildHeaders unless you're subclassing, in which case you may want to override this method
1924             with a new routine to build headers in a different fashion.
1925              
1926             This method is called internally by ->bulkmail and ->mail otherwise and is not something you need to worry about.
1927              
1928             The first time buildHeaders is called, it populates _cached_headers so as not to have to go through the processing of rebuilding
1929             the headers for each address in your list.
1930              
1931             This method is known to be able to return:
1932              
1933             MB014 - no From address
1934             MB015 - no To address
1935              
1936             =cut
1937              
1938             sub buildHeaders {
1939              
1940 2     2 1 4 my $self = shift;
1941 2         5 my $data = shift;
1942              
1943 2   33     14 my $headers_hash = shift || $self->_headers;
1944              
1945 2 50 33     9 if ($self->use_envelope && $self->_cached_headers){
    100          
1946 0         0 return $self->_cached_headers;
1947             }
1948             elsif ($self->_cached_headers){
1949              
1950 1         3 my $headers = ${$self->_cached_headers};
  1         3  
1951              
1952 1         4 my $extracted_emails = $self->extractEmail($data);
1953 1         3 my $email = $extracted_emails->{'original'};
1954              
1955 1         10 $headers =~ s/^To: ##EMAIL##/To: $email/m;
1956              
1957 1         5 return \$headers;
1958             };
1959              
1960 1         3 my $headers = undef;
1961              
1962 1         5 $headers .= "Date: " . $self->Date . "\015\012";
1963              
1964 1 50       5 if (my $from = $self->From){
1965 1         4 $headers .= "From: " . $from . "\015\012";
1966             }
1967             else {
1968 0         0 return $self->error("Cannot bulkmail...no From address", "MB014");
1969             };
1970              
1971 1 50 33     7 $headers .= "Subject: " . $self->Subject . "\015\012" if defined $self->Subject && $self->Subject =~ /\S/;
1972              
1973             #if we're using the envelope, then the To: header is the To attribute
1974 1 50       5 if (my $to = $self->use_envelope ? $self->To : "##EMAIL##"){
    50          
1975 1         4 $headers .= "To: $to\015\012";
1976             }
1977             else {
1978 0         0 return $self->error("Cannot bulkmail...no To address", "MB015");
1979             };
1980              
1981 1         4 my $sender_hash = $self->extractSender($data);
1982 1 50       4 if (defined $sender_hash) {
1983 1         5 $headers .= "Sender: " . $sender_hash->{'original'} . "\015\012";
1984             }
1985              
1986 1         6 my $reply_to_hash = $self->extractReplyTo($data);
1987 1 50       6 if (defined $reply_to_hash) {
1988 1         4 $headers .= "Reply-To: " . $reply_to_hash->{'original'} . "\015\012";
1989             };
1990              
1991             #we're always going to specify at least a list precedence
1992 1   50     6 $headers .= "Precedence: " . ($self->Precedence || 'list') . "\015\012";
1993              
1994 1 50       6 if ($headers_hash->{"Content-type"}){
1995 0         0 $headers .= "Content-type: " . $headers_hash->{"Content-type"} . "\015\012";
1996             }
1997             else {
1998 1 50       13 if ($self->HTML){
1999 0         0 $headers .= "Content-type: text/html\015\012";
2000             }
2001             else {
2002 1         2 $headers .= "Content-type: text/plain\015\012";
2003             };
2004             };
2005              
2006 1         2 foreach my $key (keys %{$headers_hash}) {
  1         8  
2007 0 0       0 next if $key eq 'Content-type';
2008 0         0 my $val = $headers_hash->{$key};
2009              
2010 0 0 0     0 next if ! defined $val || $val !~ /\S/;
2011              
2012 0         0 $headers .= $key . ": " . $val . "\015\012";
2013             };
2014              
2015             # I'm taking credit for the mailing, dammit!
2016 1         5 $headers .= "X-Bulkmail: " . $Mail::Bulkmail::VERSION . "\015\012";
2017              
2018 1         6 $headers = $self->_force_wrap_string($headers, 'start with a blank', 'no blank lines');
2019              
2020 1         3 $headers .= "\015\012"; #blank line between the header and the message
2021              
2022 1         5 $self->_cached_headers(\$headers);
2023              
2024 1 50       4 unless ($self->use_envelope){
2025 1         2 my $h = $headers; #can't just use $headers, we'll screw up the ref in _cached_headers
2026 1         5 my $extracted_emails = $self->extractEmail($data);
2027 1         3 my $email = $extracted_emails->{'original'};
2028 1         12 $h =~ s/^To: ##EMAIL##/To: $email/m;
2029 1         19 return \$h;
2030             };
2031              
2032 0         0 return \$headers;
2033              
2034             };
2035              
2036             =pod
2037              
2038             =item buildMessage
2039              
2040             buildMessage is mainly used internally, like its name implies, it builds the body of the message
2041              
2042             You'll never need to call buildMessage unless you're subclassing, in which case you may want to override this method
2043             with a new routine to build your message in a different fashion.
2044              
2045             This method is called internally by ->bulkmail and ->mail otherwise and is not something you need to worry about.
2046              
2047             This method is known to be able to return:
2048              
2049             MB016 - ->Message is not defined
2050              
2051             =cut
2052              
2053             sub buildMessage {
2054 2     2 1 3 my $self = shift;
2055              
2056 2         5 my $data = shift;
2057              
2058             #if we've cached the message, then return it
2059 2 100 66     8 return $self->_cached_message if $self->_cached_message && $self->_current_message;
2060              
2061             #otherwise, use the Message, cache that and return it.
2062 1   50     7 my $message = $self->Message()
2063             || return $self->error("Cannot build message w/o message", "MB016");
2064              
2065 1 50       6 return $message if ref $message;
2066              
2067             #sendmail-ify our line breaks
2068 1         10 $message =~ s/(?:\r?\n|\r\n?)/\015\012/g;
2069              
2070 1         4 $message = $self->_force_wrap_string($message);
2071              
2072             #double any periods that start lines
2073 1         4 $message =~ s/^\./../gm;
2074              
2075             #and force a CRLF at the end, unless one is already present
2076 1 50       5 $message .= "\015\012" unless $message =~ /\015\012$/;
2077 1         2 $message .= ".";
2078              
2079 1         5 $self->_cached_message(\$message);
2080 1         5 return \$message;
2081             };
2082              
2083             =pod
2084              
2085             =item bulkmail
2086              
2087             This is the bread and butter of the whole set up, and it's easy as pie.
2088              
2089             $bulk->bulkmail();
2090              
2091             will take your list, iterate over it, build all your message headers, build your message, and email to everyone on your
2092             list, iterating through all of your servers, log all relevant information, and send you happily on your way.
2093              
2094             Easy as pie. You don't even need to worry about it if you subclass things, because you'd just need to override
2095             buildHeaders, buildMessage, getNextLine and extractEmail at most.
2096              
2097             This method is known to be able to return:
2098              
2099             MB017 - duplicate email
2100             MB018 - banned email
2101             MB019 - invalid sender/from
2102              
2103             =cut
2104              
2105             sub bulkmail {
2106 1     1 1 91 my $self = shift;
2107              
2108 1   50     7 my $server = $self->nextServer || return undef;
2109              
2110 1         2 my $last_data = undef;
2111              
2112 1         12 while (defined (my $data = $self->getNextLine)){
2113              
2114 3 50       17 if (my $r = $server->reached_limit){
2115              
2116             #if a message is waiting on the previous server, then finish it off
2117 0 0       0 if ($self->_waiting_message) {
2118              
2119 0         0 my $headers = $self->buildHeaders($last_data);
2120              
2121 0         0 my $message = $self->buildMessage($last_data);
2122              
2123             # it is *imperative* that we only send DATA if we have the headers and message body.
2124             # otherwise, the server will hang.
2125 0 0 0     0 if ($headers && $message) {
2126 0         0 my $rc = $server->talk_and_respond("DATA");
2127 0 0       0 $server->talk_and_respond($$headers . $$message) if $rc;
2128             }
2129              
2130 0         0 my $extracted_emails = $self->extractEmail($last_data);
2131 0 0       0 if (defined $extracted_emails) {
2132 0         0 $self->setDuplicate($extracted_emails->{'extracted'});
2133             };
2134             };
2135              
2136 0   0     0 $server = $self->nextServer || return undef;
2137              
2138             #new server, so nothing should be waiting, and there are no cached domains
2139 0         0 $self->_waiting_message(0);
2140 0         0 $self->_cached_domain(undef);
2141              
2142             #and reset that server's counters
2143 0         0 $server->reset_message_counters();
2144             };
2145              
2146 3 50       31 $data =~ s/(?:^\s+|\s+$)//g unless ref $data;
2147              
2148 3   50     9 $data = $self->preprocess($data) || next;
2149              
2150 3   100     12 my $extracted_emails = $self->extractEmail($data) || next;
2151 2         7 my $email = $extracted_emails->{'extracted'};
2152              
2153             #check for duplicates or banned addresses
2154 2 50       10 if ($self->isDuplicate($email)){
    50          
2155              
2156 0 0       0 $self->logToFile($self->BAD, $data) if $self->BAD;
2157              
2158 0         0 $self->error("Invalid email address $email : duplicate", "MB017");
2159 0         0 next;
2160             }
2161             elsif (my $b = $self->isBanned($email)){
2162              
2163 0 0       0 $self->logToFile($self->BAD, $data) if $self->BAD;
2164              
2165 0 0       0 $self->error("Invalid email address $email : " . ($b == 2 ? 'banned domain' : 'banned address'), "MB018");
2166 0         0 next;
2167             };
2168              
2169             #use the envelope, if we're using it
2170 2 50       11 if ($self->use_envelope){
2171              
2172             #extract the domain from the email address
2173 0         0 (my $domain = lc $email) =~ s/^[^@]+@//;
2174              
2175             #first, see if this is a new domain, either the first time through, if it's a different domain than the last
2176             #one we saw, or if we reached the server's envelope limit
2177 0 0 0     0 if (! $self->_cached_domain || ($self->_cached_domain && $domain ne $self->_cached_domain()) || $server->reached_envelope_limit) {
      0        
      0        
2178              
2179             #if a message is waiting, then finish it off
2180 0 0       0 if ($self->_waiting_message) {
2181 0         0 my $headers = $self->buildHeaders($last_data);
2182              
2183 0         0 my $message = $self->buildMessage($last_data);
2184              
2185             # it is *imperative* that we only send DATA if we have the headers and message body.
2186             # otherwise, the server will hang.
2187 0 0 0     0 if ($headers && $message) {
2188 0         0 my $rc = $server->talk_and_respond("DATA");
2189 0 0       0 $server->talk_and_respond($$headers . $$message) if $rc;
2190             }
2191              
2192 0         0 my $extracted_emails = $self->extractEmail($last_data);
2193 0 0       0 if (defined $extracted_emails) {
2194 0         0 $self->setDuplicate($extracted_emails->{'extracted'});
2195             };
2196              
2197 0         0 $self->_waiting_message(0);
2198             };
2199              
2200             #reset our connection, just to be safe
2201              
2202 0 0       0 $server->talk_and_respond("RSET") || next;
2203              
2204 0   0     0 my $from_hash = $self->extractSender($data)
2205             || return $self->error("Could not get valid sender/from address", "MB019");
2206              
2207 0         0 my $from = $from_hash->{'extracted'};
2208              
2209             #say who the message is from
2210 0 0       0 $server->talk_and_respond("MAIL FROM:<" . $from . ">") || next;
2211              
2212             #now, since we know that we reset and sent MAIL FROM properly, we'll reset our counter
2213             #and cache this domain
2214              
2215             #reset that server's envelope counter
2216 0         0 $server->reset_envelope_counter();
2217              
2218             #so now we want to cache this domain
2219 0         0 $self->_cached_domain($domain);
2220              
2221             };
2222              
2223             #now, we add this email address to the envelope
2224 0 0       0 $server->talk_and_respond("RCPT TO:<" . $email . ">") || next;
2225              
2226             #a message is now waiting to be sent
2227 0         0 $self->_waiting_message(1);
2228              
2229             #make a note of the email address in the log
2230 0 0       0 $self->logToFile($self->GOOD, $data) if $self->GOOD;
2231              
2232             #we need to keep track of the last email sent, to finish off the final
2233             #waiting_message at the end.
2234 0         0 $last_data = $data;
2235              
2236             #and finally, we cache the domain
2237 0         0 $self->_cached_domain($domain);
2238              
2239             }
2240              
2241             #not using the envelope
2242             else {
2243 2 50       10 $self->mail($data, $server) || next;
2244             };
2245              
2246             #make a note of this email address
2247 2         11 $self->setDuplicate($email);
2248              
2249             #and we increment our counters
2250 2         18 $server->increment_messages_sent();
2251              
2252             };
2253              
2254             #if a message is waiting, then finish it off
2255 1 50       6 if ($self->_waiting_message) {
2256              
2257 0         0 my $headers = $self->buildHeaders($last_data);
2258              
2259 0         0 my $message = $self->buildMessage($last_data);
2260              
2261             # it is *imperative* that we only send DATA if we have the headers and message body.
2262             # otherwise, the server will hang.
2263 0 0 0     0 if ($headers && $message) {
2264 0         0 my $rc = $server->talk_and_respond("DATA");
2265 0 0       0 $server->talk_and_respond($$headers . $$message) if $rc;
2266             }
2267              
2268 0         0 my $extracted_emails = $self->extractEmail($last_data);
2269 0 0       0 if (defined $extracted_emails) {
2270 0         0 $self->setDuplicate($extracted_emails->{'extracted'});
2271             };
2272              
2273 0         0 $self->_waiting_message(0);
2274             };
2275              
2276 1         5 return 1;
2277              
2278             };
2279              
2280             =pod
2281              
2282             =item mail
2283              
2284             Works the same as ->bulkmail, but only operates on one email address instead of a list.
2285              
2286             $bulk->mail('jim@jimandkoka.com');
2287              
2288             Sends your Message as defined in ->Message to jim@jimandkoka.com. You can also optionally pass in a server as the second argument.
2289              
2290             $bulk->mail('jim@jimandkoka.com', $server);
2291              
2292             is the same as above, but relays through that particular server. if you don't pass a server, if tries to bring the next one
2293             in via ->nextServer
2294              
2295             ->mail wants its first argument to be whatever would be normally returned by a call to ->getNextLine($bulk->LIST); Right now,
2296             that's just a single email address. But that may change in a subclass. So, if you're operating in a subclass, just remember that
2297             you may be able (or required) to pass additional information in your first argument.
2298              
2299             This method is known to be able to return:
2300              
2301             MB018 - banned email
2302             MB019 - invalid sender/from address
2303              
2304             =cut
2305              
2306             sub mail {
2307 2     2 1 3 my $self = shift;
2308 2         5 my $data = shift;
2309 2         3 my $passed_server = shift;
2310              
2311 2   50     12 my $server = $passed_server || $self->nextServer() || return undef;
2312              
2313 2         8 $data = $self->preprocess($data);
2314              
2315 2   50     6 my $extracted_emails = $self->extractEmail($data) || return undef;
2316 2         6 my $email = $extracted_emails->{'extracted'};
2317              
2318 2 50       7 if (my $b = $self->isBanned($email)){
2319              
2320 0 0       0 $self->logToFile($self->BAD, $data) if $self->BAD;
2321              
2322 0 0       0 return $self->error("Invalid email address $email : " . ($b == 2 ? 'banned domain' : 'banned address'), "MB018");
2323             };
2324              
2325             #reset our connection, just to be safe
2326              
2327 2 50       17 $server->talk_and_respond("RSET")
2328             || return $self->error($server->error, $server->errcode, 'not logged');
2329              
2330 2   50     10 my $from_hash = $self->extractSender($data)
2331             || return $self->error("Could not get valid sender/from address", "MB019");
2332              
2333 2         5 my $from = $from_hash->{'extracted'};
2334              
2335             #say who the message is from
2336 2 50       11 $server->talk_and_respond("MAIL FROM:<" . $from . ">")
2337             || return $self->error($server->error, $server->errcode, 'not logged');
2338              
2339             #now, we add this email address to the envelope
2340 2 50       14 $server->talk_and_respond("RCPT TO:<" . $email . ">")
2341             || return $self->error($server->error, $server->errcode, 'not logged');
2342              
2343             #we build the headers and message body FIRST, to make sure we have them.
2344             #that way, we can never send DATA w/o a message and hang the server
2345 2   50     20 my $headers = $self->buildHeaders($data) || return undef;
2346              
2347 2   50     9 my $message = $self->buildMessage($data) || return undef;
2348              
2349 2 50       9 $server->talk_and_respond("DATA")
2350             || return $self->error($server->error, $server->errcode, 'not logged');
2351              
2352 2 50       12 $server->talk_and_respond($$headers . $$message) || return undef;
2353              
2354             #make a note of the email address in the log
2355 2 50       14 $self->logToFile($self->GOOD, $data) if $self->GOOD;
2356              
2357 2         19 return $email;
2358             };
2359              
2360             1;
2361              
2362             __END__