bulkmail 0.2 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,90 @@
1
+ require 'net/smtp'
2
+
3
+ module BulkMail
4
+ # Sender instances perform the actual work of sending an email. Each sender
5
+ # sets up a thread pool (by default with up to 20 threads) for performing the
6
+ # work. When creating a Sender instance, a hash of options is supplied:
7
+ #
8
+ # BulkMail::Sender.new({
9
+ # :list => addresses,
10
+ # :from => my_address,
11
+ # :helo => my_helo_domain,
12
+ # :concurrent => 50, # size of thread pool
13
+ # :message => message
14
+ # })
15
+ #
16
+ # To start sending, invoke Sender#start. The start method will block until
17
+ # all addresses have been processed.
18
+ class Sender
19
+ # Initializes a new instance with the supplied options hash, and creates a
20
+ # thread pool (with a default maximum size of 20).
21
+ def initialize(opts)
22
+ @opts = opts
23
+ @pool = ThreadPool.new(@opts[:concurrent] || 20)
24
+ @smtp_servers = {}
25
+ @mutex = Mutex.new
26
+ end
27
+
28
+ # Starts processing the addresses by sending each one a message, and waits
29
+ # for the thread pool to finish its work.
30
+ def start
31
+ @opts[:list].each {|a| @pool.process {send(a)}}
32
+ @pool.join
33
+ end
34
+
35
+ # returns an array of SMTP servers for the email address. If an invalid
36
+ # address is specified, an error is raised. SMTP servers for each email
37
+ # domain are memoized to improve performance.
38
+ def smtp_servers_for_addr(addr)
39
+ if (addr =~ /<(.*)@(.*)>/) or (addr =~ /(.*)@(.*)/)
40
+ domain = $2
41
+ else
42
+ raise RuntimeError, "Invalid email address."
43
+ end
44
+ @mutex.synchronize do
45
+ @smtp_servers[domain] ||= BulkMail.smtp_servers_for_domain(domain)
46
+ end
47
+ end
48
+
49
+ # Sends an email to a recipient by trying any of the SMTP servers available
50
+ # for the recipient.
51
+ def send(addr)
52
+ servers = smtp_servers_for_addr(addr)
53
+ if servers.empty?
54
+ report_addr(addr, :error, 'Unknown domain')
55
+ return
56
+ end
57
+ servers.each do |server|
58
+ begin
59
+ send_message(server, addr)
60
+ report_addr(addr, :success)
61
+ return
62
+ rescue => e
63
+ report_addr(addr, :error, e.message)
64
+ end
65
+ end
66
+ end
67
+
68
+ # Opens a connection to an SMTP server and sends the message.
69
+ def send_message(server, addr)
70
+ Net::SMTP.start(
71
+ server, nil, @opts[:helo], nil, nil, nil) do |smtp|
72
+ smtp.send_message @opts[:message].to_s, @opts[:from], addr
73
+ end
74
+ end
75
+
76
+ # Reports success or failure for the recipient.
77
+ def report_addr(addr, status, error = nil)
78
+ @mutex.synchronize do
79
+ case status
80
+ when :success:
81
+ puts "Sent mail to #{addr}"
82
+ File.open('sent.bulkmail', 'a') {|f| f.puts "#{addr}"}
83
+ when :error:
84
+ puts "Failed to send to #{addr}: #{error}"
85
+ File.open('failed.bulkmail', 'a') {|f| f.puts "#{addr}: #{error}"}
86
+ end
87
+ end
88
+ end
89
+ end
90
+ end
@@ -0,0 +1,113 @@
1
+ require 'thread'
2
+
3
+ # This class implements a pool of threads. The pool hands out blocks to be
4
+ # processed to any available worker thread. If no worker thread is available,
5
+ # the pool blocks until any of the workers have become available. The pool
6
+ # size can be specified when constructing the pool. For exmaple:
7
+ #
8
+ # pool = ThreadPool.new(10)
9
+ # 10.times {pool.process {sleep 3}}
10
+ # 10.times {pool.process {sleep 3}} # this will block for about 3 seconds.
11
+ # pool.join # this will block for about 3 more seconds.
12
+ class ThreadPool
13
+ # The Worker class starts a thread for performing work. A worker thread
14
+ # sleeps until it receives a block for processing, at which time it is
15
+ # considered busy. Once the block has been processed, the worker is
16
+ # considered available again.
17
+ class Worker
18
+ # Starts the worker thread.
19
+ def initialize
20
+ @mutex = Mutex.new
21
+ @thread = Thread.new do
22
+ while true
23
+ sleep 0.001
24
+ block = get_block
25
+ if block
26
+ block.call
27
+ reset_block
28
+ end
29
+ end
30
+ end
31
+ end
32
+
33
+ # Returns the block to be processed, if any.
34
+ def get_block
35
+ @mutex.synchronize {@block}
36
+ end
37
+
38
+ # Sets the block to be processed.
39
+ def set_block(block)
40
+ @mutex.synchronize {@block = block}
41
+ end
42
+
43
+ # Resets the block instance variable to signify that the worker
44
+ # is available.
45
+ def reset_block
46
+ @mutex.synchronize {@block = nil}
47
+ end
48
+
49
+ # Returns true if the worker is busy processing a block.
50
+ def busy?
51
+ @mutex.synchronize {!@block.nil?}
52
+ end
53
+ end
54
+
55
+ attr_accessor :max_size
56
+ attr_reader :workers
57
+
58
+ # Creates a new pool with a default maximum size of 10.
59
+ def initialize(max_size = 10)
60
+ @max_size = max_size
61
+ @workers = []
62
+ @mutex = Mutex.new
63
+ end
64
+
65
+ # Returns the number of workers in the pool.
66
+ def size
67
+ @mutex.synchronize {@workers.size}
68
+ end
69
+
70
+ # Returns true if any of the workers in the pool are busy.
71
+ def busy?
72
+ @mutex.synchronize {@workers.any? {|w| w.busy?}}
73
+ end
74
+
75
+ # Blocks until all workers have become available.
76
+ def join
77
+ sleep 0.01 while busy?
78
+ end
79
+
80
+ # Hands the block to an available worker. If no workers are available, this
81
+ # method will block until one becomes available.
82
+ def process(&block)
83
+ wait_for_worker.set_block(block)
84
+ end
85
+
86
+ # Waits for a worker to become available.
87
+ def wait_for_worker
88
+ while true
89
+ worker = find_available_worker
90
+ return worker if worker
91
+ sleep 0.01
92
+ end
93
+ end
94
+
95
+ # Returns an available worker or a new worker if the maximum pool size
96
+ # has not been reached.
97
+ def find_available_worker
98
+ @mutex.synchronize {free_worker || create_worker}
99
+ end
100
+
101
+ # Returns the first available worker.
102
+ def free_worker
103
+ @workers.each {|w| return w unless w.busy?}; nil
104
+ end
105
+
106
+ # Creates a worker if the maximum pool size has not been reached.
107
+ def create_worker
108
+ return nil if @workers.size >= @max_size
109
+ worker = Worker.new
110
+ @workers << worker
111
+ worker
112
+ end
113
+ end
metadata CHANGED
@@ -3,8 +3,8 @@ rubygems_version: 0.9.0
3
3
  specification_version: 1
4
4
  name: bulkmail
5
5
  version: !ruby/object:Gem::Version
6
- version: "0.2"
7
- date: 2006-10-27 00:00:00 +02:00
6
+ version: 0.3.0
7
+ date: 2007-01-12 00:00:00 +02:00
8
8
  summary: Ruby bulk-mailer.
9
9
  require_paths:
10
10
  - lib
@@ -34,24 +34,13 @@ files:
34
34
  - Rakefile
35
35
  - bin/bulkmail
36
36
  - doc/rdoc
37
- - doc/rdoc/classes
38
37
  - doc/rdoc/created.rid
39
- - doc/rdoc/files
40
- - doc/rdoc/fr_class_index.html
41
- - doc/rdoc/fr_file_index.html
42
- - doc/rdoc/fr_method_index.html
43
- - doc/rdoc/index.html
44
- - doc/rdoc/rdoc-style.css
45
- - doc/rdoc/classes/Array.html
46
- - doc/rdoc/classes/BulkMail.html
47
- - doc/rdoc/classes/String.html
48
- - doc/rdoc/classes/Symbol.html
49
- - doc/rdoc/files/CHANGELOG.html
50
- - doc/rdoc/files/COPYING.html
51
- - doc/rdoc/files/lib
52
- - doc/rdoc/files/README.html
53
- - doc/rdoc/files/lib/bulkmail_rb.html
38
+ - lib/bulkmail
54
39
  - lib/bulkmail.rb
40
+ - lib/bulkmail/dns_mx.rb
41
+ - lib/bulkmail/message.rb
42
+ - lib/bulkmail/sender.rb
43
+ - lib/bulkmail/thread_pool.rb
55
44
  - CHANGELOG
56
45
  test_files: []
57
46
 
@@ -79,5 +68,13 @@ extensions: []
79
68
 
80
69
  requirements: []
81
70
 
82
- dependencies: []
83
-
71
+ dependencies:
72
+ - !ruby/object:Gem::Dependency
73
+ name: pNet-DNS
74
+ version_requirement:
75
+ version_requirements: !ruby/object:Gem::Version::Requirement
76
+ requirements:
77
+ - - ">"
78
+ - !ruby/object:Gem::Version
79
+ version: 0.0.0
80
+ version:
@@ -1,155 +0,0 @@
1
- <?xml version="1.0" encoding="iso-8859-1"?>
2
- <!DOCTYPE html
3
- PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
4
- "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
5
-
6
- <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
7
- <head>
8
- <title>Class: Array</title>
9
- <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
10
- <meta http-equiv="Content-Script-Type" content="text/javascript" />
11
- <link rel="stylesheet" href=".././rdoc-style.css" type="text/css" media="screen" />
12
- <script type="text/javascript">
13
- // <![CDATA[
14
-
15
- function popupCode( url ) {
16
- window.open(url, "Code", "resizable=yes,scrollbars=yes,toolbar=no,status=no,height=150,width=400")
17
- }
18
-
19
- function toggleCode( id ) {
20
- if ( document.getElementById )
21
- elem = document.getElementById( id );
22
- else if ( document.all )
23
- elem = eval( "document.all." + id );
24
- else
25
- return false;
26
-
27
- elemStyle = elem.style;
28
-
29
- if ( elemStyle.display != "block" ) {
30
- elemStyle.display = "block"
31
- } else {
32
- elemStyle.display = "none"
33
- }
34
-
35
- return true;
36
- }
37
-
38
- // Make codeblocks hidden by default
39
- document.writeln( "<style type=\"text/css\">div.method-source-code { display: none }</style>" )
40
-
41
- // ]]>
42
- </script>
43
-
44
- </head>
45
- <body>
46
-
47
-
48
-
49
- <div id="classHeader">
50
- <table class="header-table">
51
- <tr class="top-aligned-row">
52
- <td><strong>Class</strong></td>
53
- <td class="class-name-in-header">Array</td>
54
- </tr>
55
- <tr class="top-aligned-row">
56
- <td><strong>In:</strong></td>
57
- <td>
58
- <a href="../files/lib/bulkmail_rb.html">
59
- lib/bulkmail.rb
60
- </a>
61
- <br />
62
- </td>
63
- </tr>
64
-
65
- <tr class="top-aligned-row">
66
- <td><strong>Parent:</strong></td>
67
- <td>
68
- Object
69
- </td>
70
- </tr>
71
- </table>
72
- </div>
73
- <!-- banner header -->
74
-
75
- <div id="bodyContent">
76
-
77
-
78
-
79
- <div id="contextContent">
80
-
81
-
82
-
83
- </div>
84
-
85
- <div id="method-list">
86
- <h3 class="section-bar">Methods</h3>
87
-
88
- <div class="name-list">
89
- <a href="#M000007">split</a>&nbsp;&nbsp;
90
- </div>
91
- </div>
92
-
93
- </div>
94
-
95
-
96
- <!-- if includes -->
97
-
98
- <div id="section">
99
-
100
-
101
-
102
-
103
-
104
-
105
-
106
-
107
- <!-- if method_list -->
108
- <div id="methods">
109
- <h3 class="section-bar">Public Instance methods</h3>
110
-
111
- <div id="method-M000007" class="method-detail">
112
- <a name="M000007"></a>
113
-
114
- <div class="method-heading">
115
- <a href="#M000007" class="method-signature">
116
- <span class="method-name">split</span><span class="method-args">(batch)</span>
117
- </a>
118
- </div>
119
-
120
- <div class="method-description">
121
- <p>
122
- Splits the array into smaller arrays of fixed size
123
- </p>
124
- <p><a class="source-toggle" href="#"
125
- onclick="toggleCode('M000007-source');return false;">[Source]</a></p>
126
- <div class="method-source-code" id="M000007-source">
127
- <pre>
128
- <span class="ruby-comment cmt"># File lib/bulkmail.rb, line 27</span>
129
- 27: <span class="ruby-keyword kw">def</span> <span class="ruby-identifier">split</span>(<span class="ruby-identifier">batch</span>)
130
- 28: <span class="ruby-identifier">result</span> = []
131
- 29: <span class="ruby-identifier">idx</span> = <span class="ruby-value">0</span>
132
- 30: <span class="ruby-keyword kw">while</span> <span class="ruby-identifier">idx</span> <span class="ruby-operator">&lt;</span> <span class="ruby-identifier">size</span>
133
- 31: <span class="ruby-identifier">result</span> <span class="ruby-operator">&lt;&lt;</span> <span class="ruby-identifier">slice</span>(<span class="ruby-identifier">idx</span>, <span class="ruby-identifier">batch</span>)
134
- 32: <span class="ruby-identifier">idx</span> <span class="ruby-operator">+=</span> <span class="ruby-identifier">batch</span>
135
- 33: <span class="ruby-keyword kw">end</span>
136
- 34: <span class="ruby-identifier">result</span>
137
- 35: <span class="ruby-keyword kw">end</span>
138
- </pre>
139
- </div>
140
- </div>
141
- </div>
142
-
143
-
144
- </div>
145
-
146
-
147
- </div>
148
-
149
-
150
- <div id="validator-badges">
151
- <p><small><a href="http://validator.w3.org/check/referer">[Validate]</a></small></p>
152
- </div>
153
-
154
- </body>
155
- </html>
@@ -1,310 +0,0 @@
1
- <?xml version="1.0" encoding="iso-8859-1"?>
2
- <!DOCTYPE html
3
- PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
4
- "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
5
-
6
- <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
7
- <head>
8
- <title>Class: BulkMail</title>
9
- <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
10
- <meta http-equiv="Content-Script-Type" content="text/javascript" />
11
- <link rel="stylesheet" href=".././rdoc-style.css" type="text/css" media="screen" />
12
- <script type="text/javascript">
13
- // <![CDATA[
14
-
15
- function popupCode( url ) {
16
- window.open(url, "Code", "resizable=yes,scrollbars=yes,toolbar=no,status=no,height=150,width=400")
17
- }
18
-
19
- function toggleCode( id ) {
20
- if ( document.getElementById )
21
- elem = document.getElementById( id );
22
- else if ( document.all )
23
- elem = eval( "document.all." + id );
24
- else
25
- return false;
26
-
27
- elemStyle = elem.style;
28
-
29
- if ( elemStyle.display != "block" ) {
30
- elemStyle.display = "block"
31
- } else {
32
- elemStyle.display = "none"
33
- }
34
-
35
- return true;
36
- }
37
-
38
- // Make codeblocks hidden by default
39
- document.writeln( "<style type=\"text/css\">div.method-source-code { display: none }</style>" )
40
-
41
- // ]]>
42
- </script>
43
-
44
- </head>
45
- <body>
46
-
47
-
48
-
49
- <div id="classHeader">
50
- <table class="header-table">
51
- <tr class="top-aligned-row">
52
- <td><strong>Class</strong></td>
53
- <td class="class-name-in-header">BulkMail</td>
54
- </tr>
55
- <tr class="top-aligned-row">
56
- <td><strong>In:</strong></td>
57
- <td>
58
- <a href="../files/lib/bulkmail_rb.html">
59
- lib/bulkmail.rb
60
- </a>
61
- <br />
62
- </td>
63
- </tr>
64
-
65
- <tr class="top-aligned-row">
66
- <td><strong>Parent:</strong></td>
67
- <td>
68
- Object
69
- </td>
70
- </tr>
71
- </table>
72
- </div>
73
- <!-- banner header -->
74
-
75
- <div id="bodyContent">
76
-
77
-
78
-
79
- <div id="contextContent">
80
-
81
-
82
-
83
- </div>
84
-
85
- <div id="method-list">
86
- <h3 class="section-bar">Methods</h3>
87
-
88
- <div class="name-list">
89
- <a href="#M000002">format_headers</a>&nbsp;&nbsp;
90
- <a href="#M000005">send_bulk</a>&nbsp;&nbsp;
91
- <a href="#M000004">send_message</a>&nbsp;&nbsp;
92
- <a href="#M000001">server_settings</a>&nbsp;&nbsp;
93
- <a href="#M000003">smtp</a>&nbsp;&nbsp;
94
- </div>
95
- </div>
96
-
97
- </div>
98
-
99
-
100
- <!-- if includes -->
101
-
102
- <div id="section">
103
-
104
-
105
- <div id="constants-list">
106
- <h3 class="section-bar">Constants</h3>
107
-
108
- <div class="name-list">
109
- <table summary="Constants">
110
- <tr class="top-aligned-row context-row">
111
- <td class="context-item-name">LINE_BREAK</td>
112
- <td>=</td>
113
- <td class="context-item-value">&quot;\r\n&quot;</td>
114
- </tr>
115
- <tr class="top-aligned-row context-row">
116
- <td class="context-item-name">HEADER_FMT</td>
117
- <td>=</td>
118
- <td class="context-item-value">&quot;%s: %s\r\n&quot;.freeze</td>
119
- </tr>
120
- </table>
121
- </div>
122
- </div>
123
-
124
-
125
-
126
-
127
-
128
-
129
- <!-- if method_list -->
130
- <div id="methods">
131
- <h3 class="section-bar">Public Class methods</h3>
132
-
133
- <div id="method-M000002" class="method-detail">
134
- <a name="M000002"></a>
135
-
136
- <div class="method-heading">
137
- <a href="#M000002" class="method-signature">
138
- <span class="method-name">format_headers</span><span class="method-args">(headers)</span>
139
- </a>
140
- </div>
141
-
142
- <div class="method-description">
143
- <p>
144
- Returns the message headers formatted
145
- </p>
146
- <p><a class="source-toggle" href="#"
147
- onclick="toggleCode('M000002-source');return false;">[Source]</a></p>
148
- <div class="method-source-code" id="M000002-source">
149
- <pre>
150
- <span class="ruby-comment cmt"># File lib/bulkmail.rb, line 57</span>
151
- 57: <span class="ruby-keyword kw">def</span> <span class="ruby-keyword kw">self</span>.<span class="ruby-identifier">format_headers</span>(<span class="ruby-identifier">headers</span>)
152
- 58: <span class="ruby-identifier">headers</span>.<span class="ruby-identifier">inject</span>(<span class="ruby-value str">''</span>) <span class="ruby-keyword kw">do</span> <span class="ruby-operator">|</span><span class="ruby-identifier">m</span>, <span class="ruby-identifier">kv</span><span class="ruby-operator">|</span>
153
- 59: <span class="ruby-identifier">m</span> <span class="ruby-operator">&lt;&lt;</span> (<span class="ruby-constant">HEADER_FMT</span> <span class="ruby-operator">%</span> [<span class="ruby-identifier">kv</span>[<span class="ruby-value">0</span>].<span class="ruby-identifier">to_header</span>, <span class="ruby-identifier">kv</span>[<span class="ruby-value">1</span>]])
154
- 60: <span class="ruby-keyword kw">end</span>
155
- 61: <span class="ruby-keyword kw">end</span>
156
- </pre>
157
- </div>
158
- </div>
159
- </div>
160
-
161
- <div id="method-M000005" class="method-detail">
162
- <a name="M000005"></a>
163
-
164
- <div class="method-heading">
165
- <a href="#M000005" class="method-signature">
166
- <span class="method-name">send_bulk</span><span class="method-args">(sender, recipients, body, headers)</span>
167
- </a>
168
- </div>
169
-
170
- <div class="method-description">
171
- <p>
172
- Sends bulk mail to a large number of recipients.
173
- </p>
174
- <p><a class="source-toggle" href="#"
175
- onclick="toggleCode('M000005-source');return false;">[Source]</a></p>
176
- <div class="method-source-code" id="M000005-source">
177
- <pre>
178
- <span class="ruby-comment cmt"># File lib/bulkmail.rb, line 89</span>
179
- 89: <span class="ruby-keyword kw">def</span> <span class="ruby-keyword kw">self</span>.<span class="ruby-identifier">send_bulk</span>(<span class="ruby-identifier">sender</span>, <span class="ruby-identifier">recipients</span>, <span class="ruby-identifier">body</span>, <span class="ruby-identifier">headers</span>)
180
- 90: <span class="ruby-identifier">failed</span> = []
181
- 91: <span class="ruby-identifier">succeeded</span> = []
182
- 92: <span class="ruby-identifier">headers</span>[<span class="ruby-identifier">:from</span>] = <span class="ruby-identifier">headers</span>[<span class="ruby-identifier">:to</span>] = <span class="ruby-identifier">sender</span>
183
- 93: <span class="ruby-identifier">recipients</span> = <span class="ruby-identifier">recipients</span>.<span class="ruby-identifier">map</span> {<span class="ruby-operator">|</span><span class="ruby-identifier">r</span><span class="ruby-operator">|</span> <span class="ruby-identifier">r</span>.<span class="ruby-identifier">email_addr</span>}.<span class="ruby-identifier">compact</span>
184
- 94: <span class="ruby-identifier">recipients</span>.<span class="ruby-identifier">split</span>(<span class="ruby-value">10</span>).<span class="ruby-identifier">each</span> <span class="ruby-keyword kw">do</span> <span class="ruby-operator">|</span><span class="ruby-identifier">list</span><span class="ruby-operator">|</span>
185
- 95: <span class="ruby-keyword kw">begin</span>
186
- 96: <span class="ruby-identifier">smtp</span> {<span class="ruby-operator">|</span><span class="ruby-identifier">s</span><span class="ruby-operator">|</span> <span class="ruby-identifier">send_message</span>(<span class="ruby-identifier">s</span>, <span class="ruby-identifier">sender</span>.<span class="ruby-identifier">email_addr</span>, <span class="ruby-identifier">list</span>, <span class="ruby-identifier">body</span>, <span class="ruby-identifier">headers</span>)}
187
- 97: <span class="ruby-identifier">succeeded</span>.<span class="ruby-identifier">concat</span> <span class="ruby-identifier">list</span>
188
- 98: <span class="ruby-identifier">puts</span> <span class="ruby-node">&quot;Sent message to #{list.join(', ')}&quot;</span>
189
- 99: <span class="ruby-keyword kw">rescue</span> =<span class="ruby-operator">&gt;</span> <span class="ruby-identifier">e</span>
190
- 100: <span class="ruby-identifier">failed</span>.<span class="ruby-identifier">concat</span> <span class="ruby-identifier">list</span>
191
- 101: <span class="ruby-identifier">puts</span> <span class="ruby-node">&quot;Failed to send to #{list.join(', ')}: #{e.message}\r\n#{e.backtrace.first}&quot;</span>
192
- 102: <span class="ruby-keyword kw">end</span>
193
- 103: <span class="ruby-keyword kw">end</span>
194
- 104: <span class="ruby-comment cmt"># log failed addresses</span>
195
- 105: <span class="ruby-keyword kw">unless</span> <span class="ruby-identifier">failed</span>.<span class="ruby-identifier">empty?</span>
196
- 106: <span class="ruby-constant">File</span>.<span class="ruby-identifier">open</span>(<span class="ruby-value str">'failed.bulkmail'</span>, <span class="ruby-value str">'w'</span>) {<span class="ruby-operator">|</span><span class="ruby-identifier">f</span><span class="ruby-operator">|</span> <span class="ruby-identifier">failed</span>.<span class="ruby-identifier">each</span> {<span class="ruby-operator">|</span><span class="ruby-identifier">l</span><span class="ruby-operator">|</span><span class="ruby-identifier">f</span>.<span class="ruby-identifier">puts</span> <span class="ruby-identifier">l</span>}}
197
- 107: <span class="ruby-keyword kw">end</span>
198
- 108: <span class="ruby-identifier">puts</span> <span class="ruby-node">&quot;Message to sent to #{succeeded.size} of #{recipients.size} recipients&quot;</span>
199
- 109: <span class="ruby-keyword kw">end</span>
200
- </pre>
201
- </div>
202
- </div>
203
- </div>
204
-
205
- <div id="method-M000004" class="method-detail">
206
- <a name="M000004"></a>
207
-
208
- <div class="method-heading">
209
- <a href="#M000004" class="method-signature">
210
- <span class="method-name">send_message</span><span class="method-args">(smtp, from, to, body, headers = nil)</span>
211
- </a>
212
- </div>
213
-
214
- <div class="method-description">
215
- <p>
216
- Sends an email
217
- </p>
218
- <p><a class="source-toggle" href="#"
219
- onclick="toggleCode('M000004-source');return false;">[Source]</a></p>
220
- <div class="method-source-code" id="M000004-source">
221
- <pre>
222
- <span class="ruby-comment cmt"># File lib/bulkmail.rb, line 77</span>
223
- 77: <span class="ruby-keyword kw">def</span> <span class="ruby-keyword kw">self</span>.<span class="ruby-identifier">send_message</span>(<span class="ruby-identifier">smtp</span>, <span class="ruby-identifier">from</span>, <span class="ruby-identifier">to</span>, <span class="ruby-identifier">body</span>, <span class="ruby-identifier">headers</span> = <span class="ruby-keyword kw">nil</span>)
224
- 78: <span class="ruby-keyword kw">if</span> <span class="ruby-identifier">headers</span> <span class="ruby-operator">&amp;&amp;</span> <span class="ruby-operator">!</span><span class="ruby-identifier">headers</span>.<span class="ruby-identifier">empty?</span>
225
- 79: <span class="ruby-identifier">msg</span> = <span class="ruby-identifier">format_headers</span>(<span class="ruby-identifier">headers</span>)
226
- 80: <span class="ruby-keyword kw">else</span>
227
- 81: <span class="ruby-identifier">msg</span> = <span class="ruby-constant">LINE_BREAK</span>
228
- 82: <span class="ruby-keyword kw">end</span>
229
- 83: <span class="ruby-identifier">msg</span> <span class="ruby-operator">&lt;&lt;</span> <span class="ruby-constant">LINE_BREAK</span>
230
- 84: <span class="ruby-identifier">msg</span> <span class="ruby-operator">&lt;&lt;</span> <span class="ruby-identifier">body</span>
231
- 85: <span class="ruby-identifier">smtp</span>.<span class="ruby-identifier">send_message</span> <span class="ruby-identifier">msg</span>, <span class="ruby-identifier">from</span>, <span class="ruby-identifier">to</span>
232
- 86: <span class="ruby-keyword kw">end</span>
233
- </pre>
234
- </div>
235
- </div>
236
- </div>
237
-
238
- <div id="method-M000001" class="method-detail">
239
- <a name="M000001"></a>
240
-
241
- <div class="method-heading">
242
- <a href="#M000001" class="method-signature">
243
- <span class="method-name">server_settings</span><span class="method-args">()</span>
244
- </a>
245
- </div>
246
-
247
- <div class="method-description">
248
- <p>
249
- Returns the <a href="BulkMail.html#M000001">server_settings</a> hash
250
- </p>
251
- <p><a class="source-toggle" href="#"
252
- onclick="toggleCode('M000001-source');return false;">[Source]</a></p>
253
- <div class="method-source-code" id="M000001-source">
254
- <pre>
255
- <span class="ruby-comment cmt"># File lib/bulkmail.rb, line 49</span>
256
- 49: <span class="ruby-keyword kw">def</span> <span class="ruby-keyword kw">self</span>.<span class="ruby-identifier">server_settings</span>
257
- 50: <span class="ruby-ivar">@@server_settings</span>
258
- 51: <span class="ruby-keyword kw">end</span>
259
- </pre>
260
- </div>
261
- </div>
262
- </div>
263
-
264
- <div id="method-M000003" class="method-detail">
265
- <a name="M000003"></a>
266
-
267
- <div class="method-heading">
268
- <a href="#M000003" class="method-signature">
269
- <span class="method-name">smtp</span><span class="method-args">() {|smtp| ...}</span>
270
- </a>
271
- </div>
272
-
273
- <div class="method-description">
274
- <p>
275
- Starts an SMTP session and yields
276
- </p>
277
- <p><a class="source-toggle" href="#"
278
- onclick="toggleCode('M000003-source');return false;">[Source]</a></p>
279
- <div class="method-source-code" id="M000003-source">
280
- <pre>
281
- <span class="ruby-comment cmt"># File lib/bulkmail.rb, line 64</span>
282
- 64: <span class="ruby-keyword kw">def</span> <span class="ruby-keyword kw">self</span>.<span class="ruby-identifier">smtp</span>
283
- 65: <span class="ruby-constant">Net</span><span class="ruby-operator">::</span><span class="ruby-constant">SMTP</span>.<span class="ruby-identifier">start</span>(
284
- 66: <span class="ruby-ivar">@@server_settings</span>[<span class="ruby-identifier">:host</span>],
285
- 67: <span class="ruby-ivar">@@server_settings</span>[<span class="ruby-identifier">:port</span>],
286
- 68: <span class="ruby-ivar">@@server_settings</span>[<span class="ruby-identifier">:helo_domain</span>] <span class="ruby-operator">||</span> <span class="ruby-ivar">@@server_settings</span>[<span class="ruby-identifier">:host</span>],
287
- 69: <span class="ruby-ivar">@@server_settings</span>[<span class="ruby-identifier">:user</span>],
288
- 70: <span class="ruby-ivar">@@server_settings</span>[<span class="ruby-identifier">:password</span>],
289
- 71: <span class="ruby-ivar">@@server_settings</span>[<span class="ruby-identifier">:auth</span>]) <span class="ruby-keyword kw">do</span> <span class="ruby-operator">|</span><span class="ruby-identifier">smtp</span><span class="ruby-operator">|</span>
290
- 72: <span class="ruby-keyword kw">yield</span> <span class="ruby-identifier">smtp</span>
291
- 73: <span class="ruby-keyword kw">end</span>
292
- 74: <span class="ruby-keyword kw">end</span>
293
- </pre>
294
- </div>
295
- </div>
296
- </div>
297
-
298
-
299
- </div>
300
-
301
-
302
- </div>
303
-
304
-
305
- <div id="validator-badges">
306
- <p><small><a href="http://validator.w3.org/check/referer">[Validate]</a></small></p>
307
- </div>
308
-
309
- </body>
310
- </html>