simple_mailing_list 0.1.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.
- checksums.yaml +7 -0
- data/.gitignore +9 -0
- data/Gemfile +6 -0
- data/Gemfile.lock +52 -0
- data/LICENSE.txt +21 -0
- data/README.ja.md +78 -0
- data/README.md +31 -0
- data/Rakefile +2 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/example/config_example.ja.yaml +127 -0
- data/example/config_example.yaml +89 -0
- data/exe/daemons_simple_mailing_list +14 -0
- data/exe/simple_mailing_list +5 -0
- data/lib/simple_mailing_list/configfile.rb +87 -0
- data/lib/simple_mailing_list/delete_old.rb +45 -0
- data/lib/simple_mailing_list/lock.rb +22 -0
- data/lib/simple_mailing_list/main.rb +394 -0
- data/lib/simple_mailing_list/setup.rb +56 -0
- data/lib/simple_mailing_list/version.rb +3 -0
- data/lib/simple_mailing_list.rb +134 -0
- data/simple_mailing_list.gemspec +35 -0
- metadata +179 -0
@@ -0,0 +1,394 @@
|
|
1
|
+
require "json"
|
2
|
+
require "securerandom"
|
3
|
+
require "digest/sha2"
|
4
|
+
|
5
|
+
require "liquid"
|
6
|
+
|
7
|
+
require "simple_mailing_list/lock"
|
8
|
+
|
9
|
+
class User < ActiveRecord::Base ; end
|
10
|
+
class Confirmation < ActiveRecord::Base ; end
|
11
|
+
|
12
|
+
module SimpleMailingList
|
13
|
+
module System
|
14
|
+
private
|
15
|
+
|
16
|
+
def _check_mails(thread_join = true)
|
17
|
+
threads = receive_mails.map do |mail_filename|
|
18
|
+
Thread.start(File.join(@maillogs_dir, "temp", mail_filename)) do |filename|
|
19
|
+
_check_mail_file(filename)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
threads.each { |thread| thread.join } if thread_join
|
23
|
+
end
|
24
|
+
|
25
|
+
def _check_mail_file(filename)
|
26
|
+
mail = Mail.read(filename)
|
27
|
+
begin
|
28
|
+
return if register_mail(mail, filename)
|
29
|
+
return if delete_mail(mail, filename)
|
30
|
+
return if confirm_mail(mail, filename)
|
31
|
+
return if bounced_mail(mail, filename)
|
32
|
+
return if forward_mail(mail, filename)
|
33
|
+
return if unmatched_mail(mail, filename)
|
34
|
+
rescue => e
|
35
|
+
move_mail_file(filename, "error")
|
36
|
+
@log.error "Error Mail[#{File.basename(filename)}]!\n #{error_message(e)}"
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def find_rule(rules, mail)
|
41
|
+
mail_body = mail.body ? mail.body.decoded.to_s : ""
|
42
|
+
mail_body += mail.text_part.decoded.to_s if mail.text_part
|
43
|
+
return rules.find do |rule|
|
44
|
+
(!rule["address"] || Array(mail.to).index(rule["address"])) &&
|
45
|
+
(!rule["subject"] || mail.subject.to_s.index(rule["subject"])) &&
|
46
|
+
(!rule["body" ] || mail_body.index(rule["body"]))
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def register_mail(mail, filename)
|
51
|
+
rule = find_rule(@register, mail)
|
52
|
+
address = Array(mail.from).first.to_s
|
53
|
+
return false if !rule || address.empty?
|
54
|
+
regisiter_options = rule["options"] || {}
|
55
|
+
@log.info "New register mail from #{address}."
|
56
|
+
return true if Confirmation.where(mail_address: address).size >= @max_check_times
|
57
|
+
|
58
|
+
check_code = create_check_code()
|
59
|
+
Confirmation.new(
|
60
|
+
mail_address: address,
|
61
|
+
check_code: check_code,
|
62
|
+
mode: "register",
|
63
|
+
options: JSON.generate(regisiter_options)
|
64
|
+
).save!
|
65
|
+
|
66
|
+
mail = create_mail(
|
67
|
+
to: address,
|
68
|
+
subject: @register_confirm_subject,
|
69
|
+
body: @register_confirm_body,
|
70
|
+
options: regisiter_options.merge({ "checkcode" => check_code })
|
71
|
+
)
|
72
|
+
mail.subject += check_code unless mail.subject.index(check_code)
|
73
|
+
mail.deliver!
|
74
|
+
sleep @sleep_time1
|
75
|
+
move_mail_file(filename, "register")
|
76
|
+
return true
|
77
|
+
end
|
78
|
+
|
79
|
+
def delete_mail(mail, filename)
|
80
|
+
rule = find_rule(@delete, mail)
|
81
|
+
address = Array(mail.from).first.to_s
|
82
|
+
return false if !rule || address.empty?
|
83
|
+
@log.info "New delete mail from #{address}."
|
84
|
+
return true if Confirmation.where(mail_address: address).size >= @max_check_times
|
85
|
+
|
86
|
+
check_code = create_check_code()
|
87
|
+
Confirmation.new(
|
88
|
+
mail_address: address,
|
89
|
+
check_code: check_code,
|
90
|
+
mode: "delete",
|
91
|
+
options: "{}"
|
92
|
+
).save!
|
93
|
+
|
94
|
+
mail = create_mail(
|
95
|
+
to: address,
|
96
|
+
subject: @delete_confirm_subject,
|
97
|
+
body: @delete_confirm_body,
|
98
|
+
options: { "checkcode" => check_code }
|
99
|
+
)
|
100
|
+
mail.subject += check_code unless mail.subject.index(check_code)
|
101
|
+
mail.deliver!
|
102
|
+
sleep @sleep_time1
|
103
|
+
move_mail_file(filename, "delete")
|
104
|
+
return true
|
105
|
+
end
|
106
|
+
|
107
|
+
def confirm_mail(mail, filename)
|
108
|
+
address = Array(mail.from).first.to_s
|
109
|
+
return false if address.empty?
|
110
|
+
subject = mail.subject.to_s
|
111
|
+
body = mail.body ? mail.body.decoded : ""
|
112
|
+
body += mail.text_part.decoded.to_s if mail.text_part
|
113
|
+
|
114
|
+
Confirmation.where(mail_address: address).each do |confirmation|
|
115
|
+
check_code = confirmation.check_code
|
116
|
+
next unless subject.index(check_code) || body.index(check_code)
|
117
|
+
|
118
|
+
confirm_options = {}
|
119
|
+
subject_text, body_text = case confirmation.mode
|
120
|
+
when "register"
|
121
|
+
@log.info "New register check mail from #{address}."
|
122
|
+
confirm_options = JSON.parse(confirmation.options)
|
123
|
+
_add_user(address, confirm_options)
|
124
|
+
[@register_success_subject, @register_success_body]
|
125
|
+
when "delete"
|
126
|
+
@log.info "New delete check mail from #{address}."
|
127
|
+
_delete_user(address)
|
128
|
+
[@delete_success_subject, @delete_success_body]
|
129
|
+
else
|
130
|
+
next
|
131
|
+
end
|
132
|
+
|
133
|
+
create_mail(
|
134
|
+
to: address,
|
135
|
+
subject: subject_text,
|
136
|
+
body: body_text,
|
137
|
+
reply_to: @reply_to_address,
|
138
|
+
options: confirm_options
|
139
|
+
).deliver!
|
140
|
+
sleep @sleep_time1
|
141
|
+
|
142
|
+
move_mail_file(filename, "#{confirmation.mode}_check")
|
143
|
+
confirmation.destroy
|
144
|
+
return true
|
145
|
+
end
|
146
|
+
|
147
|
+
return false
|
148
|
+
end
|
149
|
+
|
150
|
+
def bounced_mail(mail, filename)
|
151
|
+
unless mail.bounced?
|
152
|
+
return false
|
153
|
+
end
|
154
|
+
|
155
|
+
matched = mail.final_recipient.to_s.match(/;\s*([^@]+@[^@]+)/)
|
156
|
+
if matched
|
157
|
+
mail_address = matched[1]
|
158
|
+
@log.warn "Bounced mail[#{File.basename(filename)}] from #{mail_address}."
|
159
|
+
User.where(mail_address: mail_address).each do |user|
|
160
|
+
user.failed_count += 1
|
161
|
+
user.last_failed_at = Time.now
|
162
|
+
user.save
|
163
|
+
end
|
164
|
+
else
|
165
|
+
@log.warn "Bounced mail[#{File.basename(filename)}]."
|
166
|
+
end
|
167
|
+
move_mail_file(filename, "bounced")
|
168
|
+
return true
|
169
|
+
end
|
170
|
+
|
171
|
+
def forward_mail(mail, filename)
|
172
|
+
rule = find_rule(@forward, mail)
|
173
|
+
address = Array(mail.from).first.to_s
|
174
|
+
return false if !rule || address.empty?
|
175
|
+
forward_options = rule["options"] || {}
|
176
|
+
subject = mail.subject.to_s
|
177
|
+
@log.info "New forward mail from #{address}."
|
178
|
+
if @permitted_users
|
179
|
+
permitted_user = @permitted_users.find do |user|
|
180
|
+
(!user["address"] || user["address"] == address) &&
|
181
|
+
(!user["check_code"] || subject.index(["check_code"]))
|
182
|
+
end
|
183
|
+
return true unless permitted_user
|
184
|
+
subject.sub!(permitted_user["check_code"], "") if permitted_user["check_code"]
|
185
|
+
elsif @registered_user_only
|
186
|
+
return true unless User.find_by(mail_address: address)
|
187
|
+
end
|
188
|
+
danger_ext = /\.(exe|com|bat|cmd|vbs|vbe|js|jse|wsf|wsh|msc|jar|hta|scr|cpl|lnk)$/i
|
189
|
+
if mail.has_attachments?
|
190
|
+
attachment = mail.attachments.to_a.find do |attachment|
|
191
|
+
attachment.filename.to_s.match(danger_ext)
|
192
|
+
end
|
193
|
+
if attachment
|
194
|
+
@log.warn("Contains danger attachment![#{attachment}@#{File.basename(filename)}]")
|
195
|
+
return true
|
196
|
+
end
|
197
|
+
end
|
198
|
+
|
199
|
+
sendmail = create_forward_mail(mail, subject)
|
200
|
+
|
201
|
+
users = User.all.to_a.select do |user|
|
202
|
+
user_options = JSON.parse(user.options)
|
203
|
+
!forward_options.keys.any?{ |key| forward_options[key] != user_options[key] }
|
204
|
+
end
|
205
|
+
users.map! { |user| user.mail_address }
|
206
|
+
users.uniq!
|
207
|
+
users.delete(address)
|
208
|
+
|
209
|
+
domains = { "???" => [] }
|
210
|
+
users.each do |user|
|
211
|
+
domain = user.match(/@([^@]+)$/) ? $1 : "???"
|
212
|
+
domains[domain] ||= []
|
213
|
+
domains[domain].push(user)
|
214
|
+
end
|
215
|
+
max = domains.values.map(&:size).max
|
216
|
+
domains["???"][max] = address
|
217
|
+
0.upto(max) do |i|
|
218
|
+
time = Time.now
|
219
|
+
domains.each_value do |address_array|
|
220
|
+
mail_address = address_array[i]
|
221
|
+
next unless mail_address
|
222
|
+
|
223
|
+
@log.debug "Send to #{mail_address}"
|
224
|
+
sendmail.to = mail_address
|
225
|
+
begin
|
226
|
+
sendmail.deliver!
|
227
|
+
rescue => e
|
228
|
+
@log.warn "Sending Error!(#{mail_address})\n #{error_message(e)}"
|
229
|
+
User.where(mail_address: mail_address).each do |user|
|
230
|
+
user.failed_count += 1
|
231
|
+
user.last_failed_at = Time.now
|
232
|
+
user.save
|
233
|
+
end
|
234
|
+
end
|
235
|
+
sleep @sleep_time1
|
236
|
+
end
|
237
|
+
next if Time.now - time > @sleep_time2 || i+1 == max
|
238
|
+
sleep time - Time.now + @sleep_time2
|
239
|
+
end
|
240
|
+
@log.info "Forward mails to #{users.size + 1} user#{users.size > 0 ? 's' : ''}."
|
241
|
+
move_mail_file(filename, "forward")
|
242
|
+
return true
|
243
|
+
end
|
244
|
+
|
245
|
+
def unmatched_mail(mail, filename)
|
246
|
+
address = Array(mail.from).first.to_s
|
247
|
+
@log.warn "Unmatched mail[#{File.basename(filename)}] from #{address}."
|
248
|
+
move_mail_file(filename, "unmatched")
|
249
|
+
return true
|
250
|
+
end
|
251
|
+
|
252
|
+
def _add_user(address, user_options = {})
|
253
|
+
user = User.new
|
254
|
+
user.mail_address = address
|
255
|
+
user.options = JSON.generate(user_options)
|
256
|
+
user.save!
|
257
|
+
@log.info "Add user[#{address}]."
|
258
|
+
end
|
259
|
+
|
260
|
+
def _delete_user(address)
|
261
|
+
User.where(mail_address: address).destroy_all()
|
262
|
+
@log.info "Delete user[#{address}]."
|
263
|
+
end
|
264
|
+
|
265
|
+
def receive_mails()
|
266
|
+
mail_files = []
|
267
|
+
lock do
|
268
|
+
@receive_servers.each do |server|
|
269
|
+
begin
|
270
|
+
name = "#{server['options']['user_name']}@#{server['options']['address']}"
|
271
|
+
@log.debug "Check mails to #{name}."
|
272
|
+
Mail.defaults do
|
273
|
+
retriever_method(server["protocol"].to_sym, server["options"].symbolize_keys)
|
274
|
+
end
|
275
|
+
Mail.all(delete_after_find: true).each do |mail|
|
276
|
+
filename = mail_filename(mail)
|
277
|
+
File.binwrite(File.join(@maillogs_dir, "temp", filename), mail.raw_source)
|
278
|
+
@log.info "I got new mail[#{filename}]."
|
279
|
+
mail_files.push(filename)
|
280
|
+
end
|
281
|
+
rescue => e
|
282
|
+
@log.error "Mail Check Error!(#{name})\n #{error_message(e)}"
|
283
|
+
end
|
284
|
+
end
|
285
|
+
end
|
286
|
+
return mail_files
|
287
|
+
end
|
288
|
+
|
289
|
+
def create_mail(from: nil, to: nil, subject: "", body: nil, reply_to: nil, options: {})
|
290
|
+
mail = Mail.new
|
291
|
+
mail.charset = @deliver_server["charset"] || "utf-8"
|
292
|
+
from = @deliver_server["address"] unless from
|
293
|
+
mail.from = options["from"] = from if from
|
294
|
+
mail.to = options["to" ] = to if to
|
295
|
+
mail.reply_to = reply_to if reply_to
|
296
|
+
mail.subject = render_text(subject, options)
|
297
|
+
mail.body = render_text(body , options) if body
|
298
|
+
return mail
|
299
|
+
end
|
300
|
+
|
301
|
+
def create_forward_mail(mail, subject)
|
302
|
+
from = @use_address_camouflage ? Array(mail.from).first.to_s : nil
|
303
|
+
new_mail = create_mail(
|
304
|
+
from: from,
|
305
|
+
subject: subject,
|
306
|
+
reply_to: @use_address_camouflage ? nil : @reply_to_address
|
307
|
+
)
|
308
|
+
new_mail.in_reply_to = mail.in_reply_to if mail.in_reply_to
|
309
|
+
new_mail.references = mail.references if mail.references
|
310
|
+
|
311
|
+
if (@enable_html_mail || !mail.html_part)
|
312
|
+
new_mail.content_type = mail.content_type
|
313
|
+
new_mail.content_transfer_encoding = mail.content_transfer_encoding
|
314
|
+
mail_head = new_mail.to_s.sub(/\r\n\r\n.*\z/m, "\r\n\r\n")
|
315
|
+
mail_body = mail.raw_source.gsub(/(\r\n|\n|\r)/, "\r\n").sub(/\A.*?\r\n\r\n/m, "")
|
316
|
+
return Mail.read_from_string(mail_head + mail_body)
|
317
|
+
end
|
318
|
+
|
319
|
+
body_text = mail.body ? mail.body.decoded.to_s : ""
|
320
|
+
if mail.charset && !mail.charset.match(/utf-?8/i) && !mail.text_part
|
321
|
+
body_text.force_encoding(mail.charset)
|
322
|
+
body_text.encode!("utf-8")
|
323
|
+
end
|
324
|
+
body_text = mail.text_part.decoded.to_s if mail.text_part
|
325
|
+
html_text = mail.html_part && mail.html_part.decoded.to_s
|
326
|
+
new_mail.text_part = Mail::Part.new { body body_text }
|
327
|
+
new_mail.html_part = Mail::Part.new { body html_text } if @enable_html_mail && html_text
|
328
|
+
if mail.has_attachments?
|
329
|
+
mail.attachments.each do |attachment|
|
330
|
+
attachment_filename = attachment.filename.to_s
|
331
|
+
if File.extname(attachment_filename).empty?
|
332
|
+
ext = case attachment.mime_type.to_s.downcase
|
333
|
+
when "text/plain"
|
334
|
+
".txt"
|
335
|
+
when "application/pdf"
|
336
|
+
".pdf"
|
337
|
+
when "application/rtf"
|
338
|
+
".rtf"
|
339
|
+
when "application/msword"
|
340
|
+
".doc"
|
341
|
+
when "application/vnd.ms-excel"
|
342
|
+
".xls"
|
343
|
+
when "application/vnd.ms-powerpoint"
|
344
|
+
".ppt"
|
345
|
+
when "application/vnd.openxmlformats-officedocument.wordprocessingml.document"
|
346
|
+
".docx"
|
347
|
+
when "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
|
348
|
+
".xlsx"
|
349
|
+
when "application/vnd.openxmlformats-officedocument.presentationml.presentation"
|
350
|
+
".pptx"
|
351
|
+
when "application/x-js-taro"
|
352
|
+
".jtd"
|
353
|
+
when "image/gif"
|
354
|
+
".gif"
|
355
|
+
when "image/jpeg"
|
356
|
+
".jpeg"
|
357
|
+
when "image/png"
|
358
|
+
".png"
|
359
|
+
when "application/x-zip-compressed", "application/zip"
|
360
|
+
".zip"
|
361
|
+
else
|
362
|
+
""
|
363
|
+
end
|
364
|
+
attachment_filename += ext
|
365
|
+
end
|
366
|
+
new_mail.attachments[attachment_filename] = attachment.decoded
|
367
|
+
end
|
368
|
+
end
|
369
|
+
return new_mail
|
370
|
+
end
|
371
|
+
|
372
|
+
def create_check_code()
|
373
|
+
return SecureRandom.base64(9)
|
374
|
+
end
|
375
|
+
|
376
|
+
def mail_filename(mail)
|
377
|
+
Time.now.strftime("%Y%m%d-%H%M") +
|
378
|
+
"-#{Digest::SHA512.hexdigest(mail.to_s)[0,16]}.eml"
|
379
|
+
end
|
380
|
+
|
381
|
+
def render_text(text, render_options)
|
382
|
+
render_options.empty? ? text : Liquid::Template.parse(text).render(render_options)
|
383
|
+
end
|
384
|
+
|
385
|
+
def move_mail_file(filename, dir)
|
386
|
+
new_filename = File.join(@maillogs_dir, dir, File.basename(filename))
|
387
|
+
File.rename(filename, new_filename)
|
388
|
+
end
|
389
|
+
|
390
|
+
def error_message(error)
|
391
|
+
"#{error.inspect} #{error.backtrace.first}"
|
392
|
+
end
|
393
|
+
end
|
394
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
require "fileutils"
|
2
|
+
|
3
|
+
require "active_record"
|
4
|
+
|
5
|
+
module SimpleMailingList
|
6
|
+
module System
|
7
|
+
private
|
8
|
+
|
9
|
+
def _setup()
|
10
|
+
ActiveRecord::Base.transaction do |a|
|
11
|
+
ActiveRecord::Migration.create_table :users do |t|
|
12
|
+
t.text :mail_address , null: false
|
13
|
+
t.integer :failed_count , null: false, default: 0
|
14
|
+
t.timestamp :last_failed_at , null: false, default: Time.at(0)
|
15
|
+
t.text :options , null: false, default: "{}"
|
16
|
+
t.timestamps null: false
|
17
|
+
end
|
18
|
+
|
19
|
+
ActiveRecord::Migration.create_table :confirmations do |t|
|
20
|
+
t.text :mail_address , null: false
|
21
|
+
t.text :check_code , null: false
|
22
|
+
t.text :mode , null: false
|
23
|
+
t.text :options , null: false, default: "{}"
|
24
|
+
t.timestamps null: false
|
25
|
+
end
|
26
|
+
|
27
|
+
FileUtils.makedirs(
|
28
|
+
%w[
|
29
|
+
temp
|
30
|
+
register
|
31
|
+
delete
|
32
|
+
register_check
|
33
|
+
delete_check
|
34
|
+
forward
|
35
|
+
bounced
|
36
|
+
unmatched
|
37
|
+
error
|
38
|
+
].map do |dir|
|
39
|
+
File.join(@maillogs_dir, dir)
|
40
|
+
end
|
41
|
+
)
|
42
|
+
end
|
43
|
+
@log.info "Setup successed."
|
44
|
+
end
|
45
|
+
|
46
|
+
def _cleanup(delete_maillogs = false)
|
47
|
+
ActiveRecord::Base.transaction do |a|
|
48
|
+
ActiveRecord::Migration.drop_table(:users)
|
49
|
+
ActiveRecord::Migration.drop_table(:confirmations)
|
50
|
+
|
51
|
+
FileUtils.remove_entry_secure(@maillogs_dir, true) if delete_maillogs
|
52
|
+
end
|
53
|
+
@log.info "Cleanup successed."
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,134 @@
|
|
1
|
+
require "yaml"
|
2
|
+
require "logger"
|
3
|
+
|
4
|
+
require "mail"
|
5
|
+
require "active_record"
|
6
|
+
require "thor"
|
7
|
+
|
8
|
+
require "simple_mailing_list/configfile"
|
9
|
+
require "simple_mailing_list/version"
|
10
|
+
|
11
|
+
module SimpleMailingList
|
12
|
+
class CLI < Thor
|
13
|
+
include SimpleMailingList::System
|
14
|
+
package_name "SimpleMailingList"
|
15
|
+
default_command :main_jobs
|
16
|
+
map "--version" => :version
|
17
|
+
class_option :configfile,
|
18
|
+
aliases: "-c",
|
19
|
+
default: DEFAULT_CONFIGFILE,
|
20
|
+
desc: "configfile(YAML format) path."
|
21
|
+
|
22
|
+
def self.exit_on_failure?
|
23
|
+
true
|
24
|
+
end
|
25
|
+
|
26
|
+
desc "setup", "create tables and maillog_dir."
|
27
|
+
def setup()
|
28
|
+
require "simple_mailing_list/setup"
|
29
|
+
load_configfile(options[:configfile])
|
30
|
+
_setup()
|
31
|
+
end
|
32
|
+
|
33
|
+
desc "cleanup", "drop tables."
|
34
|
+
option :delete_maillogs,
|
35
|
+
default: false,
|
36
|
+
type: :boolean
|
37
|
+
def cleanup()
|
38
|
+
require "simple_mailing_list/setup"
|
39
|
+
load_configfile(options[:configfile])
|
40
|
+
_cleanup(options[:delete_maillogs])
|
41
|
+
end
|
42
|
+
|
43
|
+
desc "add_user MAIL_ADDRESS [JSON_FORMAT_OPTION]", "add a user."
|
44
|
+
def add_user(address, user_options="{}")
|
45
|
+
require "simple_mailing_list/main"
|
46
|
+
require "json"
|
47
|
+
load_configfile(options[:configfile])
|
48
|
+
_add_user(address, JSON.parse(user_options))
|
49
|
+
end
|
50
|
+
|
51
|
+
desc "delete_user MAIL_ADDRESS", "delete a user."
|
52
|
+
def delete_user(address)
|
53
|
+
require "simple_mailing_list/main"
|
54
|
+
load_configfile(options[:configfile])
|
55
|
+
_delete_user(address)
|
56
|
+
end
|
57
|
+
|
58
|
+
desc "delete_failed_users", "delete users who do not receive mails."
|
59
|
+
option :failed_count,
|
60
|
+
aliases: "-f",
|
61
|
+
default: 10,
|
62
|
+
type: :numeric
|
63
|
+
option :failed_time,
|
64
|
+
aliases: "-t",
|
65
|
+
default: 5 * 24 * 60 * 60,
|
66
|
+
type: :numeric
|
67
|
+
def delete_failed_users()
|
68
|
+
require "simple_mailing_list/delete_old"
|
69
|
+
load_configfile(options[:configfile])
|
70
|
+
_delete_failed_users(options[:failed_count], options[:failed_time])
|
71
|
+
end
|
72
|
+
|
73
|
+
desc "delete_old_confirmations", "delete old confirmations."
|
74
|
+
def delete_old_confirmations()
|
75
|
+
require "simple_mailing_list/delete_old"
|
76
|
+
load_configfile(options[:configfile])
|
77
|
+
_delete_old_confirmations()
|
78
|
+
end
|
79
|
+
|
80
|
+
desc "delete_old_maillogs", "delete old maillogs."
|
81
|
+
def delete_old_maillogs()
|
82
|
+
require "simple_mailing_list/delete_old"
|
83
|
+
load_configfile(options[:configfile])
|
84
|
+
_delete_old_maillogs()
|
85
|
+
end
|
86
|
+
|
87
|
+
desc "check_mails", "check new mails."
|
88
|
+
def check_mails()
|
89
|
+
require "simple_mailing_list/main"
|
90
|
+
load_configfile(options[:configfile])
|
91
|
+
_check_mails()
|
92
|
+
end
|
93
|
+
|
94
|
+
desc "check_mail_file [MAIL_FILE]", "check new mail from file."
|
95
|
+
def check_mail_file(mailfile)
|
96
|
+
require "simple_mailing_list/main"
|
97
|
+
load_configfile(options[:configfile])
|
98
|
+
_check_mail_file(mailfile)
|
99
|
+
end
|
100
|
+
|
101
|
+
desc "main_jobs", "check new mails and delete old confirmations and maillogs."
|
102
|
+
def main_jobs()
|
103
|
+
require "simple_mailing_list/main"
|
104
|
+
require "simple_mailing_list/delete_old"
|
105
|
+
load_configfile(options[:configfile])
|
106
|
+
_check_mails()
|
107
|
+
_delete_old_confirmations()
|
108
|
+
_delete_old_maillogs()
|
109
|
+
end
|
110
|
+
|
111
|
+
desc "loop", "loop main_jobs."
|
112
|
+
option :sleep_time,
|
113
|
+
aliases: "-s",
|
114
|
+
default: 10,
|
115
|
+
type: :numeric,
|
116
|
+
desc: "wait time on a loop."
|
117
|
+
def loop()
|
118
|
+
require "simple_mailing_list/main"
|
119
|
+
require "simple_mailing_list/delete_old"
|
120
|
+
load_configfile(options[:configfile])
|
121
|
+
loop do
|
122
|
+
_check_mails(false)
|
123
|
+
_delete_old_confirmations()
|
124
|
+
_delete_old_maillogs()
|
125
|
+
sleep options[:sleep_time]
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
desc "version", "output version."
|
130
|
+
def version()
|
131
|
+
puts "Simple Mailing List - #{SimpleMailingList::VERSION}"
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
|
2
|
+
lib = File.expand_path("../lib", __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require "simple_mailing_list/version"
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "simple_mailing_list"
|
8
|
+
spec.version = SimpleMailingList::VERSION
|
9
|
+
spec.authors = ["nodai2hITC"]
|
10
|
+
spec.email = ["nodai2h.itc@gmail.com"]
|
11
|
+
|
12
|
+
spec.summary = %q{Simple Mailing List System.}
|
13
|
+
spec.description = %q{This is a simple mailing list system.}
|
14
|
+
spec.homepage = "https://github.com/nodai2hITC/simple_mailing_list"
|
15
|
+
spec.license = "MIT"
|
16
|
+
|
17
|
+
spec.files = `git ls-files -z`.split("\x0").reject do |f|
|
18
|
+
f.match(%r{^(test|spec|features)/})
|
19
|
+
end
|
20
|
+
spec.bindir = "exe"
|
21
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
22
|
+
spec.require_paths = ["lib"]
|
23
|
+
|
24
|
+
spec.add_development_dependency "bundler", "~> 1.16"
|
25
|
+
spec.add_development_dependency "rake", "~> 10.0"
|
26
|
+
|
27
|
+
spec.add_dependency "mail"
|
28
|
+
spec.add_dependency "activerecord"
|
29
|
+
spec.add_dependency "liquid"
|
30
|
+
spec.add_dependency "daemons"
|
31
|
+
spec.add_dependency "thor"
|
32
|
+
# spec.add_dependency "mysql2"
|
33
|
+
# spec.add_dependency "pg"
|
34
|
+
spec.add_dependency "sqlite3"
|
35
|
+
end
|