kns_email_endpoint 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.
- data/.gitignore +4 -0
- data/Gemfile +15 -0
- data/Gemfile.lock +71 -0
- data/Guardfile +10 -0
- data/LICENCE +21 -0
- data/README.md +1 -0
- data/Rakefile +2 -0
- data/kns_email_endpoint.gemspec +39 -0
- data/lib/kns_email_endpoint/configuration.rb +87 -0
- data/lib/kns_email_endpoint/connection.rb +97 -0
- data/lib/kns_email_endpoint/core_extensions/class.rb +44 -0
- data/lib/kns_email_endpoint/core_extensions/hash.rb +14 -0
- data/lib/kns_email_endpoint/core_extensions/imap.rb +36 -0
- data/lib/kns_email_endpoint/core_extensions/message.rb +26 -0
- data/lib/kns_email_endpoint/core_extensions/pop3.rb +0 -0
- data/lib/kns_email_endpoint/core_extensions/test_retriever.rb +42 -0
- data/lib/kns_email_endpoint/email_endpoint.rb +88 -0
- data/lib/kns_email_endpoint/message_state.rb +89 -0
- data/lib/kns_email_endpoint/process_email.rb +123 -0
- data/lib/kns_email_endpoint/storage/abstract_storage.rb +93 -0
- data/lib/kns_email_endpoint/storage/file_storage.rb +74 -0
- data/lib/kns_email_endpoint/storage/memcache_storage.rb +72 -0
- data/lib/kns_email_endpoint/storage/storage.rb +15 -0
- data/lib/kns_email_endpoint/version.rb +3 -0
- data/lib/kns_email_endpoint.rb +19 -0
- data/spec/a18x34/.app +4 -0
- data/spec/a18x34/a18x34.krl +91 -0
- data/spec/lib/kns_email_endpoint/configuration_spec.rb +44 -0
- data/spec/lib/kns_email_endpoint/connection_spec.rb +133 -0
- data/spec/lib/kns_email_endpoint/email_endpoint_spec.rb +97 -0
- data/spec/lib/kns_email_endpoint/message_state_spec.rb +69 -0
- data/spec/lib/kns_email_endpoint/process_email_spec.rb +67 -0
- data/spec/lib/kns_email_endpoint/storage/file_storage_spec.rb +16 -0
- data/spec/lib/kns_email_endpoint/storage/memcache_storage_spec.rb +17 -0
- data/spec/lib/kns_email_endpoint/storage/shared_storage.rb +65 -0
- data/spec/lib/kns_email_endpoint/storage/storage_spec.rb +14 -0
- data/spec/test_config_file.yml +65 -0
- data/spec/test_email.eml +43 -0
- metadata +181 -0
@@ -0,0 +1,89 @@
|
|
1
|
+
require 'digest/sha1'
|
2
|
+
module KNSEmailEndpoint
|
3
|
+
class MessageState
|
4
|
+
|
5
|
+
class << self
|
6
|
+
attr_accessor :storage
|
7
|
+
|
8
|
+
def set_storage(storage, opts)
|
9
|
+
@storage = Storage.get_storage(storage, opts)
|
10
|
+
return @storage
|
11
|
+
end
|
12
|
+
|
13
|
+
def gen_unique_id(conn,msg)
|
14
|
+
raise "Message must have a valid message_id" unless msg.message_id.to_s != ""
|
15
|
+
Digest::SHA1.hexdigest "#{conn}::#{msg.message_id}::K-KEY"
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
|
20
|
+
attr_reader :message, :message_id, :retry_count, :unique_id, :state
|
21
|
+
|
22
|
+
def initialize(conn_name, message)
|
23
|
+
# setup the state
|
24
|
+
@conn_name = conn_name
|
25
|
+
@message = message
|
26
|
+
@message_id = get_message_id
|
27
|
+
@unique_id = get_unique_id
|
28
|
+
@storage = self.class.storage
|
29
|
+
raise "Unknown Storage" unless @storage
|
30
|
+
|
31
|
+
# get from storage
|
32
|
+
@storage.find_or_create(:unique_id => @unique_id, :message_id => @message_id)
|
33
|
+
@state = @storage.state
|
34
|
+
@retry_count = @storage.retry_count
|
35
|
+
|
36
|
+
# Do not auto delete email.
|
37
|
+
@message.mark_for_delete = false
|
38
|
+
|
39
|
+
end
|
40
|
+
|
41
|
+
def state=(s)
|
42
|
+
@state = s
|
43
|
+
@storage.state = @state if @storage.unique_id
|
44
|
+
@message.mark_for_delete = @state == :deleted
|
45
|
+
return @state
|
46
|
+
end
|
47
|
+
|
48
|
+
def retry
|
49
|
+
@retry_count += 1
|
50
|
+
@storage.retry_count = @retry_count
|
51
|
+
return @retry_count
|
52
|
+
end
|
53
|
+
|
54
|
+
def reset
|
55
|
+
@retry_count = 0
|
56
|
+
@storage.retry_count = @retry_count
|
57
|
+
return @retry_count
|
58
|
+
end
|
59
|
+
|
60
|
+
def reset_state
|
61
|
+
@storage.delete
|
62
|
+
@storage.create(:unique_id => @unique_id, :message_id => @message_id)
|
63
|
+
@retry_count = @storage.retry_count
|
64
|
+
@state = @storage.state
|
65
|
+
end
|
66
|
+
|
67
|
+
def delete
|
68
|
+
@storage.delete
|
69
|
+
self.state = :deleted
|
70
|
+
end
|
71
|
+
|
72
|
+
|
73
|
+
private
|
74
|
+
|
75
|
+
def get_message_id
|
76
|
+
return @message_id if @message_id
|
77
|
+
if @message.has_message_id?
|
78
|
+
@message_id = @message.message_id
|
79
|
+
else
|
80
|
+
raise "The mail message does not have a valid message_id."
|
81
|
+
end
|
82
|
+
return @message_id
|
83
|
+
end
|
84
|
+
|
85
|
+
def get_unique_id
|
86
|
+
return @unique_id ||= self.class.gen_unique_id(@conn_name, @message)
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
@@ -0,0 +1,123 @@
|
|
1
|
+
require 'work_queue'
|
2
|
+
module KNSEmailEndpoint
|
3
|
+
|
4
|
+
class ProcessEmail
|
5
|
+
# if in repeat mode, these states will be processed
|
6
|
+
$REPEATABLE_STATES = [:forwarded, :replied, :unprocessed, :error]
|
7
|
+
# if in single mode, these states will be processed
|
8
|
+
$SINGLE_STATES = [:unprocessed, :error]
|
9
|
+
|
10
|
+
class << self
|
11
|
+
|
12
|
+
def go(conn)
|
13
|
+
raise "Need config" unless Configuration[conn.name]
|
14
|
+
log = conn.conn_log
|
15
|
+
3.times { log.debug "" }
|
16
|
+
log.info "Processing Email from connection: #{conn.name}"
|
17
|
+
endpoint_opts = {
|
18
|
+
:ruleset => conn.appid,
|
19
|
+
:environment => conn.environment,
|
20
|
+
:use_session => true,
|
21
|
+
:logging => log.debug?
|
22
|
+
}
|
23
|
+
|
24
|
+
begin
|
25
|
+
queue = WorkQueue.new(Configuration.work_threads)
|
26
|
+
email_processed_count = 0
|
27
|
+
email_errors_count = 0
|
28
|
+
conn.retriever.find({
|
29
|
+
:count => :all,
|
30
|
+
:delete_after_find => true,
|
31
|
+
:what => :first,
|
32
|
+
:order => :asc
|
33
|
+
}) do |msg|
|
34
|
+
# worker enqueue
|
35
|
+
queue.enqueue_b {
|
36
|
+
begin
|
37
|
+
msg_state = MessageState.new(conn.name, msg)
|
38
|
+
log.debug "Processing Message #{msg_state.unique_id}"
|
39
|
+
log.debug "STATE: #{msg_state.state}"
|
40
|
+
if (conn.process_mode == :single && $SINGLE_STATES.include?(msg_state.state)) ||
|
41
|
+
(conn.process_mode == :repeat && $REPEATABLE_STATES.include?(msg_state.state))
|
42
|
+
|
43
|
+
ee = EmailEndpoint.new(conn.name, endpoint_opts, conn.sender)
|
44
|
+
event_args = {
|
45
|
+
:msg => msg,
|
46
|
+
:unique_id => msg_state.unique_id
|
47
|
+
}.merge! conn.event_args
|
48
|
+
|
49
|
+
log.debug "Raising Event\n #{event_args.inspect}"
|
50
|
+
result = ee.received(event_args)
|
51
|
+
if log.debug?
|
52
|
+
log.debug "--- Endpoint Log ---"
|
53
|
+
log.debug ee.log.join("\n")
|
54
|
+
log.debug "--------------------"
|
55
|
+
end
|
56
|
+
if ee.message_state.state == :processing
|
57
|
+
# there was no directive returned or endpoint failed.
|
58
|
+
log.debug "UNEXPECTED DIRECTIVE RECEIVED: \n#{result.inspect}"
|
59
|
+
raise "No directive matched message (#{msg.message_id})"
|
60
|
+
|
61
|
+
end
|
62
|
+
log.debug "NEW STATE: " + ee.message_state.state.to_s
|
63
|
+
log.debug "Delete message? #{msg.is_marked_for_delete?}"
|
64
|
+
else
|
65
|
+
log.debug "Skipping #{msg.message_id} (#{msg_state.state})"
|
66
|
+
log.debug "Delete message? #{msg.is_marked_for_delete?}"
|
67
|
+
end
|
68
|
+
email_processed_count += 1
|
69
|
+
|
70
|
+
rescue => e
|
71
|
+
rc = msg_state.retry
|
72
|
+
if rc >= (conn.max_retry_count - 1)
|
73
|
+
msg_state.state = :failed
|
74
|
+
else
|
75
|
+
msg_state.state = :error
|
76
|
+
end
|
77
|
+
log.error e.message
|
78
|
+
log.error "RETRY COUNT: #{rc}"
|
79
|
+
log.error "NEW STATE: #{msg_state.state}"
|
80
|
+
log.error "Delete message? #{msg.is_marked_for_delete?}"
|
81
|
+
email_errors_count += 1
|
82
|
+
end
|
83
|
+
|
84
|
+
}
|
85
|
+
queue.join
|
86
|
+
end
|
87
|
+
log.info "Number of email successfully processed for connection #{conn.name}: #{email_processed_count}"
|
88
|
+
log.info "Number of email unsuccesfully processed for connection #{conn.name}: #{email_errors_count}"
|
89
|
+
rescue => e
|
90
|
+
log.error "There was an error processing email for #{conn.name}: #{e.message}"
|
91
|
+
end
|
92
|
+
|
93
|
+
|
94
|
+
end
|
95
|
+
|
96
|
+
def go_async
|
97
|
+
threads = []
|
98
|
+
begin
|
99
|
+
Configuration.each_connection do |conn|
|
100
|
+
threads << Thread.new { go conn }
|
101
|
+
end
|
102
|
+
threads.each { |t| t.join }
|
103
|
+
rescue => e
|
104
|
+
Configuration.log.error e.message
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
def go_all
|
109
|
+
begin
|
110
|
+
Configuration.each_connection { |conn| go conn }
|
111
|
+
rescue => e
|
112
|
+
Configuration.log.error e.message
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
def flush
|
117
|
+
# flush all message states
|
118
|
+
Configuration.storage_engine.delete_all
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
end
|
123
|
+
end
|
@@ -0,0 +1,93 @@
|
|
1
|
+
module KNSEmailEndpoint
|
2
|
+
module Storage
|
3
|
+
class AbstractStorage
|
4
|
+
attr_reader :message_id, :unique_id, :retry_count, :state
|
5
|
+
|
6
|
+
def initialize(*args)
|
7
|
+
|
8
|
+
reset_storage
|
9
|
+
end
|
10
|
+
|
11
|
+
# delete should return either true if successful, or false if unsuccessful
|
12
|
+
# delete should also call reset_storage if successful
|
13
|
+
def delete
|
14
|
+
return false # override me
|
15
|
+
|
16
|
+
end
|
17
|
+
|
18
|
+
# create should call set_vars and save! if successful and return true
|
19
|
+
# otherwise, it should raise an exception
|
20
|
+
def create(opts={})
|
21
|
+
return false #override me
|
22
|
+
|
23
|
+
end
|
24
|
+
|
25
|
+
# find should return self if a record is found after calling set_vars
|
26
|
+
# it should return nil if not found and call reset_storage
|
27
|
+
def find(unique_id)
|
28
|
+
return nil #override me
|
29
|
+
end
|
30
|
+
|
31
|
+
def retry_count=(r)
|
32
|
+
raise "Unknown unique_id" unless @unique_id
|
33
|
+
@retry_count = r
|
34
|
+
save!
|
35
|
+
end
|
36
|
+
|
37
|
+
def state=(s)
|
38
|
+
raise "Unknown unique_id" unless @unique_id
|
39
|
+
@state = s
|
40
|
+
save!
|
41
|
+
end
|
42
|
+
|
43
|
+
def to_h
|
44
|
+
return {} unless @unique_id
|
45
|
+
return {
|
46
|
+
:unique_id => @unique_id,
|
47
|
+
:message_id => @message_id,
|
48
|
+
:retry_count => @retry_count,
|
49
|
+
:state => @state
|
50
|
+
}
|
51
|
+
end
|
52
|
+
|
53
|
+
def find_or_create(opts={})
|
54
|
+
unless opts[:unique_id] && opts[:message_id]
|
55
|
+
raise "Must provide at least a unique_id and message_id"
|
56
|
+
end
|
57
|
+
|
58
|
+
s = find(opts[:unique_id])
|
59
|
+
return s if s
|
60
|
+
|
61
|
+
return create(opts) ? self : nil
|
62
|
+
end
|
63
|
+
|
64
|
+
private
|
65
|
+
|
66
|
+
def save!
|
67
|
+
# override me
|
68
|
+
end
|
69
|
+
|
70
|
+
def set_vars(h)
|
71
|
+
h.symbolize_keys!
|
72
|
+
raise "Invalid unique_id" unless h[:unique_id]
|
73
|
+
raise "Invalid message_id" unless h[:message_id]
|
74
|
+
raise "Invalid retry_count" unless h[:retry_count]
|
75
|
+
raise "Invalid state" unless h[:state]
|
76
|
+
@unique_id = h[:unique_id]
|
77
|
+
@message_id = h[:message_id]
|
78
|
+
@retry_count = h[:retry_count]
|
79
|
+
@state = h[:state].to_sym
|
80
|
+
|
81
|
+
end
|
82
|
+
|
83
|
+
def reset_storage
|
84
|
+
@unique_id = nil
|
85
|
+
@message_id = nil
|
86
|
+
@retry_count = nil
|
87
|
+
@state = nil
|
88
|
+
@current_file = nil
|
89
|
+
end
|
90
|
+
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
require 'json'
|
2
|
+
require 'fileutils'
|
3
|
+
module KNSEmailEndpoint
|
4
|
+
module Storage
|
5
|
+
class FileStorage < AbstractStorage
|
6
|
+
attr_reader :name
|
7
|
+
|
8
|
+
def initialize(settings={})
|
9
|
+
@dir = settings[:file_location]
|
10
|
+
raise "Unknown file_location" unless @dir
|
11
|
+
FileUtils.mkdir_p @dir
|
12
|
+
|
13
|
+
super(settings)
|
14
|
+
@name = "file"
|
15
|
+
|
16
|
+
end
|
17
|
+
|
18
|
+
def delete
|
19
|
+
return false unless @current_file
|
20
|
+
FileUtils.rm @current_file if File.exists? @current_file
|
21
|
+
reset_storage
|
22
|
+
return true
|
23
|
+
end
|
24
|
+
|
25
|
+
def create(opts={})
|
26
|
+
options = {
|
27
|
+
:state => :unprocessed,
|
28
|
+
:retry_count => 0
|
29
|
+
}.merge! opts
|
30
|
+
raise ":unique_id is required" unless options[:unique_id]
|
31
|
+
raise ":message_id is required" unless options[:message_id]
|
32
|
+
|
33
|
+
@current_file = File.join(@dir, options[:unique_id])
|
34
|
+
|
35
|
+
if File.exists? @current_file
|
36
|
+
raise "unique_id #{options[:unique_id]} already exists"
|
37
|
+
end
|
38
|
+
|
39
|
+
set_vars(options)
|
40
|
+
save!
|
41
|
+
|
42
|
+
return true
|
43
|
+
end
|
44
|
+
|
45
|
+
def find(unique_id)
|
46
|
+
lookup_file = File.join(@dir, unique_id)
|
47
|
+
if File.exists? lookup_file
|
48
|
+
@current_file = lookup_file
|
49
|
+
set_vars JSON.parse(File.open(@current_file, 'r').read)
|
50
|
+
return self
|
51
|
+
else
|
52
|
+
reset_storage
|
53
|
+
return nil
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def delete_all
|
58
|
+
FileUtils.remove_dir(@dir, true)
|
59
|
+
FileUtils.mkdir_p @dir
|
60
|
+
end
|
61
|
+
|
62
|
+
|
63
|
+
private
|
64
|
+
|
65
|
+
def save!
|
66
|
+
File.open(@current_file, "w") do |f|
|
67
|
+
f.write to_h.to_json
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
require 'dalli'
|
2
|
+
module KNSEmailEndpoint
|
3
|
+
module Storage
|
4
|
+
class MemcacheStorage < AbstractStorage
|
5
|
+
class << self
|
6
|
+
attr_accessor :client
|
7
|
+
end
|
8
|
+
|
9
|
+
def initialize(settings)
|
10
|
+
options = {
|
11
|
+
:host => "localhost",
|
12
|
+
:port => 11211,
|
13
|
+
:ttl => nil
|
14
|
+
}.merge!(settings)
|
15
|
+
|
16
|
+
|
17
|
+
# This simple bit of magic allows usage of
|
18
|
+
# a class connection rather than an instance connection
|
19
|
+
# so we never have more than one active connection to memcache
|
20
|
+
self.class.client ||= Dalli::Client.new("#{options[:host]}:#{options[:port]}")
|
21
|
+
@client = self.class.client
|
22
|
+
@ttl = options[:ttl]
|
23
|
+
|
24
|
+
end
|
25
|
+
|
26
|
+
def create(opts={})
|
27
|
+
options = {
|
28
|
+
:state => :unprocessed,
|
29
|
+
:retry_count => 0
|
30
|
+
}.merge! opts
|
31
|
+
raise ":unique_id is required" unless options[:unique_id]
|
32
|
+
raise ":message_id is required" unless options[:message_id]
|
33
|
+
|
34
|
+
set_vars(options)
|
35
|
+
save!
|
36
|
+
|
37
|
+
return true
|
38
|
+
end
|
39
|
+
|
40
|
+
def find(unique_id)
|
41
|
+
s = @client.get(unique_id)
|
42
|
+
if s
|
43
|
+
set_vars(s)
|
44
|
+
return self
|
45
|
+
else
|
46
|
+
reset_storage
|
47
|
+
return nil
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def delete
|
52
|
+
return false unless @unique_id
|
53
|
+
@client.delete @unique_id
|
54
|
+
reset_storage
|
55
|
+
return true
|
56
|
+
end
|
57
|
+
|
58
|
+
def delete_all
|
59
|
+
@client.flush
|
60
|
+
reset_storage
|
61
|
+
return true
|
62
|
+
end
|
63
|
+
|
64
|
+
private
|
65
|
+
|
66
|
+
def save!
|
67
|
+
@client.set(@unique_id, to_h, @ttl)
|
68
|
+
end
|
69
|
+
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'kns_email_endpoint/storage/abstract_storage'
|
2
|
+
module KNSEmailEndpoint
|
3
|
+
module Storage
|
4
|
+
autoload :FileStorage, 'kns_email_endpoint/storage/file_storage'
|
5
|
+
autoload :MemcacheStorage, 'kns_email_endpoint/storage/memcache_storage'
|
6
|
+
|
7
|
+
def self.get_storage(engine, settings)
|
8
|
+
case engine.to_sym
|
9
|
+
when :file then return FileStorage.new(settings)
|
10
|
+
when :memcache then return MemcacheStorage.new(settings)
|
11
|
+
else return nil
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
|
3
|
+
# require some extensions
|
4
|
+
require 'kns_email_endpoint/core_extensions/class'
|
5
|
+
require 'kns_email_endpoint/core_extensions/hash'
|
6
|
+
require 'kns_email_endpoint/core_extensions/imap'
|
7
|
+
require 'kns_email_endpoint/core_extensions/message'
|
8
|
+
require 'kns_email_endpoint/core_extensions/test_retriever'
|
9
|
+
|
10
|
+
# all the gem pieces
|
11
|
+
require 'kns_endpoint'
|
12
|
+
require 'kns_email_endpoint/connection'
|
13
|
+
require 'kns_email_endpoint/configuration'
|
14
|
+
require 'kns_email_endpoint/email_endpoint'
|
15
|
+
require 'kns_email_endpoint/storage/storage'
|
16
|
+
require 'kns_email_endpoint/message_state'
|
17
|
+
require 'kns_email_endpoint/process_email'
|
18
|
+
|
19
|
+
|
data/spec/a18x34/.app
ADDED
@@ -0,0 +1,91 @@
|
|
1
|
+
ruleset a18x34 {
|
2
|
+
meta {
|
3
|
+
name "Test App for Email Endpoint"
|
4
|
+
description <<
|
5
|
+
Testing application for the Email Endpoint
|
6
|
+
>>
|
7
|
+
author "Michael Farmer"
|
8
|
+
// Uncomment this line to require Marketplace purchase to use this app.
|
9
|
+
// authz require user
|
10
|
+
logging on
|
11
|
+
}
|
12
|
+
|
13
|
+
|
14
|
+
global {
|
15
|
+
|
16
|
+
}
|
17
|
+
|
18
|
+
rule receive_new_email is active {
|
19
|
+
select when mail received test_rule "parts"
|
20
|
+
pre {
|
21
|
+
envelope = event:param("msg");
|
22
|
+
from = event:param("from");
|
23
|
+
to = event:param("to");
|
24
|
+
subject = event:param("subject");
|
25
|
+
label = event:param("label");
|
26
|
+
unique_id = event:param("unique_id");
|
27
|
+
collection = {
|
28
|
+
"from": from,
|
29
|
+
"to": to,
|
30
|
+
"subject": subject,
|
31
|
+
"label": label,
|
32
|
+
"unique_id": unique_id
|
33
|
+
}
|
34
|
+
}
|
35
|
+
{
|
36
|
+
send_directive("processed");
|
37
|
+
}
|
38
|
+
|
39
|
+
fired {
|
40
|
+
log collection.encode();
|
41
|
+
}
|
42
|
+
|
43
|
+
}
|
44
|
+
|
45
|
+
rule delete_mail is active {
|
46
|
+
select when mail received test_rule "delete_me"
|
47
|
+
{
|
48
|
+
email:delete();
|
49
|
+
}
|
50
|
+
|
51
|
+
}
|
52
|
+
|
53
|
+
rule reply_mail is active {
|
54
|
+
select when mail received test_rule "reply"
|
55
|
+
|
56
|
+
{
|
57
|
+
email:reply() with body = "This is a reply message";
|
58
|
+
}
|
59
|
+
}
|
60
|
+
|
61
|
+
rule reply_and_delete_mail is active {
|
62
|
+
select when mail received test_rule "reply and delete"
|
63
|
+
|
64
|
+
{
|
65
|
+
email:reply() with body = "This is a reply message" and delete_message = true;
|
66
|
+
}
|
67
|
+
}
|
68
|
+
|
69
|
+
|
70
|
+
rule forward_mail is active {
|
71
|
+
select when mail received test_rule "forward"
|
72
|
+
pre {
|
73
|
+
fwd_to = event:param("forward_to");
|
74
|
+
}
|
75
|
+
{
|
76
|
+
email:forward() with to = fwd_to and body = "This is a forwarded message"
|
77
|
+
}
|
78
|
+
|
79
|
+
}
|
80
|
+
|
81
|
+
rule forward_and_delete_mail is active {
|
82
|
+
select when mail received test_rule "forward and delete"
|
83
|
+
pre {
|
84
|
+
fwd_to = event:param("forward_to");
|
85
|
+
}
|
86
|
+
{
|
87
|
+
email:forward() with to = fwd_to and body = "This is a forwarded message" and delete_message = true;
|
88
|
+
}
|
89
|
+
|
90
|
+
}
|
91
|
+
}
|
@@ -0,0 +1,44 @@
|
|
1
|
+
require 'lib/kns_email_endpoint'
|
2
|
+
|
3
|
+
$CONFIG_FILE = File.join(File.dirname(__FILE__), '../..', 'test_config_file.yml')
|
4
|
+
|
5
|
+
module KNSEmailEndpoint
|
6
|
+
describe Configuration do
|
7
|
+
|
8
|
+
Configuration.load_from_file $CONFIG_FILE
|
9
|
+
let(:c) { Configuration }
|
10
|
+
|
11
|
+
it "should have a storage engine" do
|
12
|
+
c.storage_engine.should_not be_nil
|
13
|
+
end
|
14
|
+
|
15
|
+
describe "loaded" do
|
16
|
+
|
17
|
+
specify { c.work_threads.should eql 5}
|
18
|
+
specify { c.poll_delay.should eql 30}
|
19
|
+
specify { c.logdir.should eql "/tmp/email_endpoint"}
|
20
|
+
specify { c.connections.should_not be_empty }
|
21
|
+
specify { c.storage.should_not be_empty }
|
22
|
+
specify { c.log.class.should == Logger }
|
23
|
+
specify { c.storage_engine.class.should == KNSEmailEndpoint::Storage::MemcacheStorage }
|
24
|
+
specify { c.log.level.should == 0 }
|
25
|
+
|
26
|
+
end
|
27
|
+
|
28
|
+
|
29
|
+
describe "access connections" do
|
30
|
+
|
31
|
+
it 'should return a connection by name' do
|
32
|
+
c["test"]["name"].should eql "test"
|
33
|
+
end
|
34
|
+
|
35
|
+
it "should let me loop through the connections" do
|
36
|
+
c.each_connection do |conn|
|
37
|
+
["test", "gmail"].should include(conn.name)
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
44
|
+
end
|