line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package Net::SMTP::Bulk;
|
2
|
|
|
|
|
|
|
|
3
|
1
|
|
|
1
|
|
13224
|
use 5.006;
|
|
1
|
|
|
|
|
2
|
|
4
|
1
|
|
|
1
|
|
3
|
use strict;
|
|
1
|
|
|
|
|
1
|
|
|
1
|
|
|
|
|
17
|
|
5
|
1
|
|
|
1
|
|
3
|
use warnings FATAL => 'all';
|
|
1
|
|
|
|
|
3
|
|
|
1
|
|
|
|
|
166
|
|
6
|
|
|
|
|
|
|
|
7
|
|
|
|
|
|
|
#use Encode;
|
8
|
|
|
|
|
|
|
#use Coro;
|
9
|
|
|
|
|
|
|
#use Coro::Handle;
|
10
|
|
|
|
|
|
|
#use AnyEvent::Socket;
|
11
|
|
|
|
|
|
|
|
12
|
|
|
|
|
|
|
|
13
|
|
|
|
|
|
|
=head1 NAME
|
14
|
|
|
|
|
|
|
|
15
|
|
|
|
|
|
|
Net::SMTP::Bulk - NonBlocking batch SMTP using Net::SMTP interface
|
16
|
|
|
|
|
|
|
|
17
|
|
|
|
|
|
|
=head1 VERSION
|
18
|
|
|
|
|
|
|
|
19
|
|
|
|
|
|
|
Version 0.23
|
20
|
|
|
|
|
|
|
|
21
|
|
|
|
|
|
|
=cut
|
22
|
|
|
|
|
|
|
|
23
|
|
|
|
|
|
|
our $VERSION = '0.23';
|
24
|
|
|
|
|
|
|
|
25
|
|
|
|
|
|
|
|
26
|
|
|
|
|
|
|
|
27
|
|
|
|
|
|
|
=head1 SYNOPSIS
|
28
|
|
|
|
|
|
|
|
29
|
|
|
|
|
|
|
This is a rewrite of Net::SMTP using AnyEvent and Coro as a backbone. It supports AUTH, SSL and STARTTLS as well. This module can be used as a drop in replacement for Net::SMTP. At this point this module is EXPIREMENTAL, so use at your own risk. Functionality can change at any time.
|
30
|
|
|
|
|
|
|
|
31
|
|
|
|
|
|
|
=head1 IMPORTANT
|
32
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
Before you start using this module, it is important to understand the fundementals behind it. Now I know it is tempting to skip this part but I assure you that reading this is crucial to using this module. I will try to keep it short.
|
34
|
|
|
|
|
|
|
|
35
|
|
|
|
|
|
|
First of all, let me get this out of the way, this module contains 2 methods of implementation. Method 1: Coro+AnyEvent and Method 2: AnyEvent only. These methods somewhat accomplish the same thing but bahave completely different and were created for different purposes.
|
36
|
|
|
|
|
|
|
|
37
|
|
|
|
|
|
|
=head2 METHOD 1: Coro+AnyEvent
|
38
|
|
|
|
|
|
|
|
39
|
|
|
|
|
|
|
This method was created first, it was used on a server with little ram while trying to send millions of emails. How it works is you have a server+thread queue, once the queue fills up or quit command is called, it sends the emails.
|
40
|
|
|
|
|
|
|
|
41
|
|
|
|
|
|
|
The email sending process is in order, which means it will call the MAIL FROM, RCPT TO and etc commands for all emails in the batch at the same time. If 1 email fails in a batch, it is thrown out of the batch and it is up to you to figure out how to handle it through the Callbacks. It is possible for a single command to mess up the entire batch though.
|
42
|
|
|
|
|
|
|
|
43
|
|
|
|
|
|
|
Other differences: SSL/STARTTLS handshake is negotiated by a workaround
|
44
|
|
|
|
|
|
|
|
45
|
|
|
|
|
|
|
use Net::SMTP::Bulk::Coro;
|
46
|
|
|
|
|
|
|
|
47
|
|
|
|
|
|
|
my $smtp = Net::SMTP::Bulk::Coro->new($server, %options);
|
48
|
|
|
|
|
|
|
|
49
|
|
|
|
|
|
|
=head2 METHOD 2: AnyEvent only
|
50
|
|
|
|
|
|
|
|
51
|
|
|
|
|
|
|
After I got new servers with far more ram, I wanted to prioritize speed. So I created this module, it works quite different than the Coro one and is faster but is most likely more memory intensive.
|
52
|
|
|
|
|
|
|
|
53
|
|
|
|
|
|
|
How it works is, you send all the emails to the module and once the quit command is called, all emails are processed on a first come first serve basis.
|
54
|
|
|
|
|
|
|
|
55
|
|
|
|
|
|
|
This means if you have a million emails, all those million emails are going into ram.
|
56
|
|
|
|
|
|
|
|
57
|
|
|
|
|
|
|
Other differences: SSL/STARTTLS handshake is negotiated AnyEvent::TLS
|
58
|
|
|
|
|
|
|
|
59
|
|
|
|
|
|
|
use Net::SMTP::Bulk::AnyEvent;
|
60
|
|
|
|
|
|
|
|
61
|
|
|
|
|
|
|
my $smtp = Net::SMTP::Bulk::AnyEvent->new($server, %options);
|
62
|
|
|
|
|
|
|
|
63
|
|
|
|
|
|
|
=head2 Which Method should you use?
|
64
|
|
|
|
|
|
|
|
65
|
|
|
|
|
|
|
The answer 9/10 times, METHOD 2: AnyEvent only. Why? Because I am using it. While I will go back and try to keep Method 1 up to date when I have time, Method 2 will get far more love since I am using it. If you really plan to use Method 1 and you need some function implemented to keep up with Method 2, please file it in the bug reports on CPAN. And I will prioritize it. But again, only when I have the time.
|
66
|
|
|
|
|
|
|
|
67
|
|
|
|
|
|
|
If your worry about using Method 2 comes down to ram, there are workarounds such as having it send in batches of say 1000. And while I can make Method 2 work like Method 1 fully, at this point I have no plan to. So if you are constrained by ram, try dividing up the emails in 1000 at a time for Method 2. If that doesn't work, Method 1 is your way point.
|
68
|
|
|
|
|
|
|
|
69
|
|
|
|
|
|
|
Both Methods should work for the most part. Just again, Method 2 will see more love at this point.
|
70
|
|
|
|
|
|
|
|
71
|
|
|
|
|
|
|
|
72
|
|
|
|
|
|
|
=head1 SYNTEX
|
73
|
|
|
|
|
|
|
|
74
|
|
|
|
|
|
|
See Net::SMTP and methods below for syntax.
|
75
|
|
|
|
|
|
|
|
76
|
|
|
|
|
|
|
=head1 SUBROUTINES/METHODS
|
77
|
|
|
|
|
|
|
|
78
|
|
|
|
|
|
|
=head2 new($server,%options)
|
79
|
|
|
|
|
|
|
|
80
|
|
|
|
|
|
|
=head2 new(%options)
|
81
|
|
|
|
|
|
|
|
82
|
|
|
|
|
|
|
Options:
|
83
|
|
|
|
|
|
|
Host - Hostname or IP address
|
84
|
|
|
|
|
|
|
|
85
|
|
|
|
|
|
|
Port - The port to which to connect to on the server (default: 25)
|
86
|
|
|
|
|
|
|
|
87
|
|
|
|
|
|
|
Hello - The domain name you wish to connect to (default: [same as server])
|
88
|
|
|
|
|
|
|
|
89
|
|
|
|
|
|
|
Debug - Debug information (0-10 depending on level. Higher level contains all lower levels) (default: 0, 0 - disabled, 5 - summary, 7 - hangs/fails, 8 - passes, 10 - full details) OPTIONAL
|
90
|
|
|
|
|
|
|
|
91
|
|
|
|
|
|
|
DebugPath - Set to default Debug Path. use [HOST] and [THREAD] for deeper control of output. Dates can also be appended via [YYYY] = year, [MM] = month, [DD] = day, [WK] = week, [hh] = hour, [mm] = minute OPTIONAL
|
92
|
|
|
|
|
|
|
|
93
|
|
|
|
|
|
|
Secure - If you wish to use a secure connection. ( default: 0, 0 - None, 1 - SSL [no verify], 2 - SSL [verify], 3 - STARTTLS [no verify], 4 - STARTTLS [verify]) OPTIONAL [Requires Net::SSLeay]
|
94
|
|
|
|
|
|
|
|
95
|
|
|
|
|
|
|
Threads - How many concurrent connections per host (default: 2) OPTIONAL
|
96
|
|
|
|
|
|
|
|
97
|
|
|
|
|
|
|
Encode - Encode socket( 1: utf8 )
|
98
|
|
|
|
|
|
|
|
99
|
|
|
|
|
|
|
Timeout - Amount of seconds until it gives up on the session and attempts to reconnect ( defaukt: 60 ) OPTIONAL
|
100
|
|
|
|
|
|
|
|
101
|
|
|
|
|
|
|
Hosts - An ARRAY containing a list of HASH reference of Hosts OPTIONAL
|
102
|
|
|
|
|
|
|
|
103
|
|
|
|
|
|
|
GlobalTimeout - (Method 2 only) Amount of seconds for no activity on any thread. If no activity is seen on any thread, it will reconnect on all threads. Keep in mind the delays you plan to use for Sleep and Retry. ( default: 120 ) OPTIONAL
|
104
|
|
|
|
|
|
|
|
105
|
|
|
|
|
|
|
Sleep - (Method 2 only) A HASH that sets a sleep timer in seconds for reconnect attempts. ( Default: Hang=>0, Fail => 0 ) CAVEAT: Since a timer is used the last second is not reliable, so if you set a timer of 30 seconds, it can be anywhere between 29-30 seconds. OPTIONAL
|
106
|
|
|
|
|
|
|
|
107
|
|
|
|
|
|
|
Retry - (Method 2 only) Amount of retries until it gives up. ( default: Hang=>1, GlobalHang => 1, Fail => 5 ) Put 0 for unlimited. OPTIONAL
|
108
|
|
|
|
|
|
|
|
109
|
|
|
|
|
|
|
Auth - (Method 2 only) An ARRAY containing AUTH details. ( eg. ['AUTO','user','pass'] or to force a mechanism such as LOGIN ['LOGIN','user','pass'] ) OPTIONAL
|
110
|
|
|
|
|
|
|
|
111
|
|
|
|
|
|
|
Callbacks - You can supply callback functions on certain conditions, these conditions include: OPTIONAL
|
112
|
|
|
|
|
|
|
|
113
|
|
|
|
|
|
|
Pipeline - (Method 2 only) Use pipelining for even quicker sending, makse sure server accepts pipelining. Pipelining should offer a good speed boost but may lead to more complex debugging, especially in mode 2 ( default: 0, 0 - Disabled with 4 round trips [normal], 1 - Pipelining with 2 roundtrips [faster], 2 - Pipelining with 1 roundtrip [fastest] ) OPTIONAL
|
114
|
|
|
|
|
|
|
|
115
|
|
|
|
|
|
|
Method1:
|
116
|
|
|
|
|
|
|
connect_pass,connect_fail,auth_pass,auth_fail,reconnect_pass,reconnect_fail,pass,fail,hang
|
117
|
|
|
|
|
|
|
|
118
|
|
|
|
|
|
|
The callback must return 1 it to follow proper proceedures. You can overwrite the defaults by supplying a different return.
|
119
|
|
|
|
|
|
|
|
120
|
|
|
|
|
|
|
1 - Default
|
121
|
|
|
|
|
|
|
|
122
|
|
|
|
|
|
|
101 - Remove Thread permanently
|
123
|
|
|
|
|
|
|
|
124
|
|
|
|
|
|
|
102 - Remove thread temporarily and reconnect at end of batch
|
125
|
|
|
|
|
|
|
|
126
|
|
|
|
|
|
|
103 - Remove thread temporarily and restart at end of batch (If your using an SMTP server with short timeout, it is suggested to use this over reconnect)
|
127
|
|
|
|
|
|
|
|
128
|
|
|
|
|
|
|
104 - Remove Thread temporarily
|
129
|
|
|
|
|
|
|
|
130
|
|
|
|
|
|
|
202 - Reconnect now
|
131
|
|
|
|
|
|
|
|
132
|
|
|
|
|
|
|
203 - Restart now
|
133
|
|
|
|
|
|
|
|
134
|
|
|
|
|
|
|
Method2:
|
135
|
|
|
|
|
|
|
connect_pass - connected to server
|
136
|
|
|
|
|
|
|
|
137
|
|
|
|
|
|
|
pass - Email was accepted by server
|
138
|
|
|
|
|
|
|
|
139
|
|
|
|
|
|
|
fail - This triggers if some sort of error happens, be it server did not recognize command or failed to connect. (I will most likely move fail to connect later on to connect_fail)
|
140
|
|
|
|
|
|
|
|
141
|
|
|
|
|
|
|
hang - timeout has been reached for sending to email to user, email not sent
|
142
|
|
|
|
|
|
|
|
143
|
|
|
|
|
|
|
global_hang - timeout has been reached for entire email sening operation
|
144
|
|
|
|
|
|
|
|
145
|
|
|
|
|
|
|
read - callback on every line read
|
146
|
|
|
|
|
|
|
|
147
|
|
|
|
|
|
|
The callback must return 1 it to follow proper proceedures. Other callback responses will be implemented later.
|
148
|
|
|
|
|
|
|
|
149
|
|
|
|
|
|
|
1 - Default
|
150
|
|
|
|
|
|
|
|
151
|
|
|
|
|
|
|
=head2 new(%options, Hosts=>[\%options2,\%options3])
|
152
|
|
|
|
|
|
|
|
153
|
|
|
|
|
|
|
You can supply multiple hosts in an array.
|
154
|
|
|
|
|
|
|
|
155
|
|
|
|
|
|
|
|
156
|
|
|
|
|
|
|
=head2 auth( [ MECHANISM,] USERNAME, PASSWORD )
|
157
|
|
|
|
|
|
|
|
158
|
|
|
|
|
|
|
*Requires Authen::SASL
|
159
|
|
|
|
|
|
|
|
160
|
|
|
|
|
|
|
=head2 mail( ADDRESS )
|
161
|
|
|
|
|
|
|
|
162
|
|
|
|
|
|
|
=head2 to( ADDRESS )
|
163
|
|
|
|
|
|
|
|
164
|
|
|
|
|
|
|
=head2 data()
|
165
|
|
|
|
|
|
|
|
166
|
|
|
|
|
|
|
=head2 datasend( DATA )
|
167
|
|
|
|
|
|
|
|
168
|
|
|
|
|
|
|
=head2 dataend( DATA )
|
169
|
|
|
|
|
|
|
|
170
|
|
|
|
|
|
|
=head2 reconnect( )
|
171
|
|
|
|
|
|
|
|
172
|
|
|
|
|
|
|
=head2 quit( [ID] )
|
173
|
|
|
|
|
|
|
|
174
|
|
|
|
|
|
|
*ID is Method2 only and is an optional field. It helps you track the ID through debugging. It defaults to epoch time if not passed.
|
175
|
|
|
|
|
|
|
|
176
|
|
|
|
|
|
|
=head1 CAVEATS
|
177
|
|
|
|
|
|
|
|
178
|
|
|
|
|
|
|
Other then the Caveats described above, it should he noted that there are missing functions for full SMTP compatibility.
|
179
|
|
|
|
|
|
|
|
180
|
|
|
|
|
|
|
Missing fuctions include: HELO(EHLO is used), TURN, ATURN, SIZE, ETRN, CHUNKING/BDAT, DSN, RSET, VRFY, HELP
|
181
|
|
|
|
|
|
|
|
182
|
|
|
|
|
|
|
These functions will be added as time goes on. If you need a certain function to have priority, request it .
|
183
|
|
|
|
|
|
|
=cut
|
184
|
|
|
|
|
|
|
|
185
|
|
|
|
|
|
|
sub new {
|
186
|
0
|
|
|
0
|
1
|
|
my $class=shift;
|
187
|
0
|
|
|
|
|
|
my %new=@_;
|
188
|
0
|
|
|
|
|
|
my $self={};
|
189
|
|
|
|
|
|
|
|
190
|
0
|
0
|
0
|
|
|
|
if (($new{Mode}||'') eq 'AnyEvent') {
|
191
|
0
|
|
|
|
|
|
require Net::SMTP::Bulk::AnyEvent;
|
192
|
0
|
|
|
|
|
|
$self=Net::SMTP::Bulk::AnyEvent->new(@_);
|
193
|
|
|
|
|
|
|
} else {
|
194
|
0
|
0
|
|
|
|
|
if (eval { require Net::SMTP::Bulk::Coro; 1 }) {
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
195
|
0
|
|
|
|
|
|
$self=Net::SMTP::Bulk::Coro->new(@_);
|
196
|
|
|
|
|
|
|
} else {
|
197
|
0
|
|
|
|
|
|
require Net::SMTP::Bulk::AnyEvent;
|
198
|
0
|
|
|
|
|
|
$self=Net::SMTP::Bulk::AnyEvent->new(@_);
|
199
|
|
|
|
|
|
|
}
|
200
|
|
|
|
|
|
|
|
201
|
|
|
|
|
|
|
|
202
|
|
|
|
|
|
|
}
|
203
|
|
|
|
|
|
|
|
204
|
|
|
|
|
|
|
|
205
|
|
|
|
|
|
|
|
206
|
0
|
|
|
|
|
|
return $self;
|
207
|
|
|
|
|
|
|
}
|
208
|
|
|
|
|
|
|
|
209
|
|
|
|
|
|
|
|
210
|
|
|
|
|
|
|
#########################################################################
|
211
|
|
|
|
|
|
|
|
212
|
|
|
|
|
|
|
|
213
|
|
|
|
|
|
|
=head1 AUTHOR
|
214
|
|
|
|
|
|
|
|
215
|
|
|
|
|
|
|
KnowZero
|
216
|
|
|
|
|
|
|
|
217
|
|
|
|
|
|
|
=head1 BUGS
|
218
|
|
|
|
|
|
|
|
219
|
|
|
|
|
|
|
Please report any bugs or feature requests to C, or through
|
220
|
|
|
|
|
|
|
the web interface at L. I will be notified, and then you'll
|
221
|
|
|
|
|
|
|
automatically be notified of progress on your bug as I make changes.
|
222
|
|
|
|
|
|
|
|
223
|
|
|
|
|
|
|
|
224
|
|
|
|
|
|
|
|
225
|
|
|
|
|
|
|
|
226
|
|
|
|
|
|
|
=head1 SUPPORT
|
227
|
|
|
|
|
|
|
|
228
|
|
|
|
|
|
|
You can find documentation for this module with the perldoc command.
|
229
|
|
|
|
|
|
|
|
230
|
|
|
|
|
|
|
perldoc Net::SMTP::Bulk
|
231
|
|
|
|
|
|
|
|
232
|
|
|
|
|
|
|
|
233
|
|
|
|
|
|
|
You can also look for information at:
|
234
|
|
|
|
|
|
|
|
235
|
|
|
|
|
|
|
=over 4
|
236
|
|
|
|
|
|
|
|
237
|
|
|
|
|
|
|
=item * RT: CPAN's request tracker (report bugs here)
|
238
|
|
|
|
|
|
|
|
239
|
|
|
|
|
|
|
L
|
240
|
|
|
|
|
|
|
|
241
|
|
|
|
|
|
|
=item * AnnoCPAN: Annotated CPAN documentation
|
242
|
|
|
|
|
|
|
|
243
|
|
|
|
|
|
|
L
|
244
|
|
|
|
|
|
|
|
245
|
|
|
|
|
|
|
=item * CPAN Ratings
|
246
|
|
|
|
|
|
|
|
247
|
|
|
|
|
|
|
L
|
248
|
|
|
|
|
|
|
|
249
|
|
|
|
|
|
|
=item * Search CPAN
|
250
|
|
|
|
|
|
|
|
251
|
|
|
|
|
|
|
L
|
252
|
|
|
|
|
|
|
|
253
|
|
|
|
|
|
|
=back
|
254
|
|
|
|
|
|
|
|
255
|
|
|
|
|
|
|
|
256
|
|
|
|
|
|
|
=head1 ACKNOWLEDGEMENTS
|
257
|
|
|
|
|
|
|
|
258
|
|
|
|
|
|
|
|
259
|
|
|
|
|
|
|
=head1 LICENSE AND COPYRIGHT
|
260
|
|
|
|
|
|
|
|
261
|
|
|
|
|
|
|
Copyright 2013 KnowZero.
|
262
|
|
|
|
|
|
|
|
263
|
|
|
|
|
|
|
This program is free software; you can redistribute it and/or modify it
|
264
|
|
|
|
|
|
|
under the terms of either: the GNU General Public License as published
|
265
|
|
|
|
|
|
|
by the Free Software Foundation; or the Artistic License.
|
266
|
|
|
|
|
|
|
|
267
|
|
|
|
|
|
|
See L for more information.
|
268
|
|
|
|
|
|
|
|
269
|
|
|
|
|
|
|
|
270
|
|
|
|
|
|
|
=cut
|
271
|
|
|
|
|
|
|
|
272
|
|
|
|
|
|
|
1; # End of Net::SMTP::Bulk
|