appmail 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/lib/app_mail.rb +18 -0
- data/lib/app_mail/attachment.rb +31 -0
- data/lib/app_mail/client.rb +51 -0
- data/lib/app_mail/config.rb +15 -0
- data/lib/app_mail/error.rb +47 -0
- data/lib/app_mail/header_set.rb +21 -0
- data/lib/app_mail/message.rb +156 -0
- data/lib/app_mail/message_scope.rb +40 -0
- data/lib/app_mail/send_message.rb +77 -0
- data/lib/app_mail/send_result.rb +30 -0
- data/lib/app_mail/version.rb +3 -0
- data/lib/appmail.rb +1 -0
- metadata +76 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: cf42054c6e347a5c7cad150857aa334eab7e5ea6
|
4
|
+
data.tar.gz: 6a1e0e40ed2c04a67232875132d9d2dddb4ad7ee
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: b7e91f5b55dff971e14a56a146684d23666737209459d40c01da057f985e2b1bc5903667357ae4eaea8b8cd489ebe8d87ff526f745748c673af9492f8ba40386
|
7
|
+
data.tar.gz: 9d90c3d37b84bfe5e8585d9a72607ab214b137765d2afb952d16dc144102d1562f5b9da7e2cd18fcacc171aaccd476d1162a2d84e99ead6e27c5afb8dad37970
|
data/lib/app_mail.rb
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'app_mail/client'
|
2
|
+
require 'app_mail/config'
|
3
|
+
|
4
|
+
module AppMail
|
5
|
+
|
6
|
+
def self.config
|
7
|
+
@config ||= Config.new
|
8
|
+
end
|
9
|
+
|
10
|
+
def self.configure(&block)
|
11
|
+
block.call(config)
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.send_message(&block)
|
15
|
+
AppMail::Client.instance.send_message(&block)
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'base64'
|
2
|
+
|
3
|
+
module AppMail
|
4
|
+
class Attachment
|
5
|
+
|
6
|
+
def initialize(attributes)
|
7
|
+
@attributes = attributes
|
8
|
+
end
|
9
|
+
|
10
|
+
def filename
|
11
|
+
@attributes['filename']
|
12
|
+
end
|
13
|
+
|
14
|
+
def content_type
|
15
|
+
@attributes['content_type']
|
16
|
+
end
|
17
|
+
|
18
|
+
def size
|
19
|
+
@attributes['size']
|
20
|
+
end
|
21
|
+
|
22
|
+
def hash
|
23
|
+
@attributes['hash']
|
24
|
+
end
|
25
|
+
|
26
|
+
def data
|
27
|
+
@data ||= Base64.decode64(@attributes['data'])
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
require 'moonrope_client'
|
2
|
+
require 'app_mail/message_scope'
|
3
|
+
require 'app_mail/send_message'
|
4
|
+
|
5
|
+
module AppMail
|
6
|
+
class Client
|
7
|
+
|
8
|
+
#
|
9
|
+
# Create and cache a global instance of client based on the environment variables
|
10
|
+
# which can be provided. In 90% of cases, AppMail will be accessed through this.
|
11
|
+
#
|
12
|
+
def self.instance
|
13
|
+
@instance ||= Client.new(AppMail.config.host, AppMail.config.server_key)
|
14
|
+
end
|
15
|
+
|
16
|
+
#
|
17
|
+
# Initialize a new client with the host and API key
|
18
|
+
#
|
19
|
+
def initialize(host, server_key)
|
20
|
+
@host = host
|
21
|
+
@server_key = server_key
|
22
|
+
end
|
23
|
+
|
24
|
+
#
|
25
|
+
# Provide a scope to access messages
|
26
|
+
#
|
27
|
+
def messages
|
28
|
+
MessageScope.new(self)
|
29
|
+
end
|
30
|
+
|
31
|
+
#
|
32
|
+
# Send a message
|
33
|
+
#
|
34
|
+
def send_message(&block)
|
35
|
+
message = SendMessage.new(self)
|
36
|
+
block.call(message)
|
37
|
+
message.send!
|
38
|
+
end
|
39
|
+
|
40
|
+
#
|
41
|
+
# Return the backend moonrope instance for this client
|
42
|
+
#
|
43
|
+
def moonrope
|
44
|
+
@moonrope ||= begin
|
45
|
+
headers= {'X-Server-API-Key' => @server_key}
|
46
|
+
MoonropeClient::Connection.new(@host, :headers => headers, :ssl => true)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module AppMail
|
2
|
+
class Config
|
3
|
+
|
4
|
+
def host
|
5
|
+
@host || ENV['APPMAIL_HOST'] || 'api.appmail.io'
|
6
|
+
end
|
7
|
+
attr_writer :host
|
8
|
+
|
9
|
+
def server_key
|
10
|
+
@server_key || ENV['APPMAIL_KEY'] || raise(Error, "Server key has not been configured. Set it using the `AppMail.configure` block or use `APPMAIL_KEY` environment variable.")
|
11
|
+
end
|
12
|
+
attr_writer :server_key
|
13
|
+
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
module AppMail
|
2
|
+
|
3
|
+
#
|
4
|
+
# A generic error that all errors will inherit from
|
5
|
+
#
|
6
|
+
class Error < StandardError
|
7
|
+
end
|
8
|
+
|
9
|
+
#
|
10
|
+
# Raised when a message cannot be found by its ID
|
11
|
+
#
|
12
|
+
class MessageNotFound < Error
|
13
|
+
def initialize(id)
|
14
|
+
@id = id
|
15
|
+
end
|
16
|
+
|
17
|
+
def message
|
18
|
+
"No message found matching ID '#{@id}'"
|
19
|
+
end
|
20
|
+
|
21
|
+
def to_s
|
22
|
+
message
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
#
|
27
|
+
# Raised when a message cannot be found by its ID
|
28
|
+
#
|
29
|
+
class SendError < Error
|
30
|
+
def initialize(code, error_message)
|
31
|
+
@code = code
|
32
|
+
@error_message = error_message
|
33
|
+
end
|
34
|
+
|
35
|
+
attr_reader :code
|
36
|
+
attr_reader :error_message
|
37
|
+
|
38
|
+
def message
|
39
|
+
"[#{@code}] #{@error_message}"
|
40
|
+
end
|
41
|
+
|
42
|
+
def to_s
|
43
|
+
message
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module AppMail
|
2
|
+
class HeaderSet
|
3
|
+
|
4
|
+
def initialize(headers)
|
5
|
+
@headers = headers
|
6
|
+
end
|
7
|
+
|
8
|
+
def [](name)
|
9
|
+
@headers[name.to_s.downcase]
|
10
|
+
end
|
11
|
+
|
12
|
+
def has_key?(key)
|
13
|
+
@headers.has_key?(name.to_s.downcase)
|
14
|
+
end
|
15
|
+
|
16
|
+
def method_missing(*args, &block)
|
17
|
+
@headers.send(*args, &block)
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,156 @@
|
|
1
|
+
require 'app_mail/error'
|
2
|
+
require 'app_mail/header_set'
|
3
|
+
require 'app_mail/attachment'
|
4
|
+
|
5
|
+
module AppMail
|
6
|
+
class Message
|
7
|
+
|
8
|
+
#
|
9
|
+
# Find a specific messsage with the given scope
|
10
|
+
#
|
11
|
+
def self.find_with_scope(scope, id)
|
12
|
+
api = scope.client.moonrope.messages.message(:id => id.to_i, :_expansions => scope.expansions)
|
13
|
+
if api.success?
|
14
|
+
Message.new(scope.client, api.data)
|
15
|
+
elsif api.status == 'error' && api.data['code'] == 'MessageNotFound'
|
16
|
+
raise MessageNotFound.new(id)
|
17
|
+
else
|
18
|
+
raise Error, "Couldn't load message from API (#{api.data})"
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
#
|
23
|
+
# If methods are called directly on the Message class, we likely want to see if we can
|
24
|
+
# run them through the global client message scope.
|
25
|
+
#
|
26
|
+
def self.method_missing(name, *args, &block)
|
27
|
+
if MessageScope.instance_methods(false).include?(name)
|
28
|
+
AppMail::Client.instance.messages.send(name, *args, &block)
|
29
|
+
else
|
30
|
+
super
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
#
|
35
|
+
# Initialize a new message object with the client and a set of initial attributes.
|
36
|
+
#
|
37
|
+
def initialize(client, attributes)
|
38
|
+
@client = client
|
39
|
+
@attributes = attributes
|
40
|
+
end
|
41
|
+
|
42
|
+
#
|
43
|
+
# Return the message ID
|
44
|
+
#
|
45
|
+
def id
|
46
|
+
@attributes['id']
|
47
|
+
end
|
48
|
+
|
49
|
+
#
|
50
|
+
# Return the message token
|
51
|
+
#
|
52
|
+
def token
|
53
|
+
@attributes['token']
|
54
|
+
end
|
55
|
+
|
56
|
+
#
|
57
|
+
# Set a has of all the attributes from the API that should be exposed through
|
58
|
+
# the Message class.
|
59
|
+
#
|
60
|
+
ATTRIBUTES = {
|
61
|
+
:status => [:status, :status],
|
62
|
+
:last_delivery_attempt => [:status, :last_delivery_attempt, :timestamp],
|
63
|
+
:held? => [:status, :held, :boolean],
|
64
|
+
:hold_expiry => [:status, :hold_expiry, :timestamp],
|
65
|
+
:rcpt_to => [:details, :rcpt_to],
|
66
|
+
:mail_from => [:details, :mail_from],
|
67
|
+
:subject => [:details, :subject],
|
68
|
+
:message_id => [:details, :message_id],
|
69
|
+
:timestamp => [:details, :timestamp, :timestamp],
|
70
|
+
:direction => [:details, :direction],
|
71
|
+
:size => [:details, :size],
|
72
|
+
:bounce? => [:details, :bounce, :boolean],
|
73
|
+
:bounce_for_id => [:details, :bounce],
|
74
|
+
:tag => [:details, :tag],
|
75
|
+
:received_with_ssl? => [:details, :received_with_ssl, :boolean],
|
76
|
+
:inspected? => [:inspection, :inspected, :boolean],
|
77
|
+
:spam? => [:inspection, :spam, :boolean],
|
78
|
+
:spam_score => [:inspection, :spam_score],
|
79
|
+
:threat? => [:inspection, :thret, :boolean],
|
80
|
+
:threat_details => [:inspection, :threat_details],
|
81
|
+
:plain_body => [:plain_body],
|
82
|
+
:html_body => [:html_body],
|
83
|
+
}
|
84
|
+
|
85
|
+
#
|
86
|
+
# Catch calls to any of the default attributes for a message and return the
|
87
|
+
# data however we'd like it
|
88
|
+
#
|
89
|
+
def method_missing(name, *args, &block)
|
90
|
+
if mapping = ATTRIBUTES[name.to_sym]
|
91
|
+
expansion, attribute, type = mapping
|
92
|
+
value = from_expansion(expansion, attribute)
|
93
|
+
case type
|
94
|
+
when :timestamp
|
95
|
+
value ? Time.at(value) : nil
|
96
|
+
when :boolean
|
97
|
+
value == 1
|
98
|
+
else
|
99
|
+
value
|
100
|
+
end
|
101
|
+
else
|
102
|
+
super
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
#
|
107
|
+
# Return a set of headers which can be queried like a hash however looking up
|
108
|
+
# values using [] will be case-insensitive.
|
109
|
+
#
|
110
|
+
def headers
|
111
|
+
@headers ||= HeaderSet.new(from_expansion(:headers))
|
112
|
+
end
|
113
|
+
|
114
|
+
#
|
115
|
+
# Return an array of attachment objects
|
116
|
+
#
|
117
|
+
def attachments
|
118
|
+
@attachments ||= from_expansion(:attachments).map do |a|
|
119
|
+
Attachment.new(a)
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
#
|
124
|
+
# Return the full raw message
|
125
|
+
#
|
126
|
+
def raw_message
|
127
|
+
@raw_message ||= Base64.decode64(from_expansion(:raw_message))
|
128
|
+
end
|
129
|
+
|
130
|
+
private
|
131
|
+
|
132
|
+
def from_expansion(expansion, attribute = nil, loaded = false)
|
133
|
+
if @attributes.has_key?(expansion.to_s) || loaded
|
134
|
+
attribute ? @attributes[expansion.to_s][attribute.to_s] : @attributes[expansion.to_s]
|
135
|
+
else
|
136
|
+
load_expansions(expansion)
|
137
|
+
from_expansion(expansion, attribute, true)
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
def load_expansions(*names)
|
142
|
+
puts "\e[31mLoading expansion #{names}\e[0m"
|
143
|
+
api = @client.moonrope.messages.message(:id => self.id, :_expansions => names)
|
144
|
+
if api.success?
|
145
|
+
names.each do |expansion_name|
|
146
|
+
if api.data.has_key?(expansion_name.to_s)
|
147
|
+
@attributes[expansion_name.to_s] = api.data[expansion_name.to_s]
|
148
|
+
end
|
149
|
+
end
|
150
|
+
else
|
151
|
+
raise AppMail::Error, "Couldn't load expansion data (#{names.join(', ')}) for message ID '#{self.id}'"
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
end
|
156
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
require 'app_mail/message'
|
2
|
+
|
3
|
+
module AppMail
|
4
|
+
class MessageScope
|
5
|
+
|
6
|
+
attr_reader :client
|
7
|
+
|
8
|
+
def initialize(client)
|
9
|
+
@client = client
|
10
|
+
@includes = []
|
11
|
+
end
|
12
|
+
|
13
|
+
#
|
14
|
+
# Add includes to the scope
|
15
|
+
#
|
16
|
+
def includes(*includes)
|
17
|
+
@includes.push(*includes)
|
18
|
+
self
|
19
|
+
end
|
20
|
+
|
21
|
+
#
|
22
|
+
# Return the current includes
|
23
|
+
#
|
24
|
+
def expansions
|
25
|
+
if @includes.include?(:all)
|
26
|
+
true
|
27
|
+
else
|
28
|
+
@includes.map(&:to_s)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
#
|
33
|
+
# Find a given message by its ID
|
34
|
+
#
|
35
|
+
def find_by_id(id)
|
36
|
+
Message.find_with_scope(self, id)
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,77 @@
|
|
1
|
+
require 'base64'
|
2
|
+
require 'app_mail/send_result'
|
3
|
+
|
4
|
+
module AppMail
|
5
|
+
class SendMessage
|
6
|
+
|
7
|
+
def initialize(client)
|
8
|
+
@client = client
|
9
|
+
@attributes = {}
|
10
|
+
end
|
11
|
+
|
12
|
+
def send!
|
13
|
+
api = @client.moonrope.request(:send, :message, @attributes)
|
14
|
+
if api.success?
|
15
|
+
SendResult.new(@client, api.data)
|
16
|
+
elsif api.status == 'error'
|
17
|
+
raise SendError.new(api.data['code'], api.data['message'])
|
18
|
+
else
|
19
|
+
raise Error, "Couldn't send message"
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def from(address)
|
24
|
+
@attributes[:from] = address
|
25
|
+
end
|
26
|
+
|
27
|
+
def to(*addresses)
|
28
|
+
@attributes[:to] ||= []
|
29
|
+
@attributes[:to] += addresses
|
30
|
+
end
|
31
|
+
|
32
|
+
def cc(*addresses)
|
33
|
+
@attributes[:cc] ||= []
|
34
|
+
@attributes[:cc] += addresses
|
35
|
+
end
|
36
|
+
|
37
|
+
def bcc(*addresses)
|
38
|
+
@attributes[:bcc] ||= []
|
39
|
+
@attributes[:bcc] += addresses
|
40
|
+
end
|
41
|
+
|
42
|
+
def subject(subject)
|
43
|
+
@attributes[:subject] = subject
|
44
|
+
end
|
45
|
+
|
46
|
+
def tag(tag)
|
47
|
+
@attributes[:tag] = subject
|
48
|
+
end
|
49
|
+
|
50
|
+
def reply_to(reply_to)
|
51
|
+
@attributes[:reply_to] = subject
|
52
|
+
end
|
53
|
+
|
54
|
+
def plain_body(content)
|
55
|
+
@attributes[:plain_body] = content
|
56
|
+
end
|
57
|
+
|
58
|
+
def html_body(content)
|
59
|
+
@attributes[:html_body] = content
|
60
|
+
end
|
61
|
+
|
62
|
+
def header(key, value)
|
63
|
+
@attributes[:headers] ||= {}
|
64
|
+
@attributes[:headers][key.to_s] = value
|
65
|
+
end
|
66
|
+
|
67
|
+
def attach(filename, content_type, data)
|
68
|
+
@attributes[:attachments] ||= []
|
69
|
+
@attributes[:attachments] << {
|
70
|
+
:name => filename,
|
71
|
+
:content_type => content_type,
|
72
|
+
:data => Base64.encode64(data)
|
73
|
+
}
|
74
|
+
end
|
75
|
+
|
76
|
+
end
|
77
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module AppMail
|
2
|
+
class SendResult
|
3
|
+
|
4
|
+
def initialize(client, result)
|
5
|
+
@client = client
|
6
|
+
@result = result
|
7
|
+
end
|
8
|
+
|
9
|
+
def message_id
|
10
|
+
@result['message_id']
|
11
|
+
end
|
12
|
+
|
13
|
+
def recipients
|
14
|
+
@recipients ||= begin
|
15
|
+
@result['messages'].each_with_object({}) do |(recipient, message_details), hash|
|
16
|
+
hash[recipient.to_s.downcase] = Message.new(@client, message_details)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def [](recipient)
|
22
|
+
recipients[recipient.to_s.downcase]
|
23
|
+
end
|
24
|
+
|
25
|
+
def size
|
26
|
+
recipients.size
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
30
|
+
end
|
data/lib/appmail.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require 'app_mail'
|
metadata
ADDED
@@ -0,0 +1,76 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: appmail
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Adam Cooke
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2016-10-29 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: moonrope-client
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 1.0.2
|
20
|
+
- - "<"
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: '1.1'
|
23
|
+
type: :runtime
|
24
|
+
prerelease: false
|
25
|
+
version_requirements: !ruby/object:Gem::Requirement
|
26
|
+
requirements:
|
27
|
+
- - ">="
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: 1.0.2
|
30
|
+
- - "<"
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: '1.1'
|
33
|
+
description: Ruby library for the AppMail E-Mail Platform
|
34
|
+
email:
|
35
|
+
- me@adamcooke.io
|
36
|
+
executables: []
|
37
|
+
extensions: []
|
38
|
+
extra_rdoc_files: []
|
39
|
+
files:
|
40
|
+
- lib/app_mail.rb
|
41
|
+
- lib/app_mail/attachment.rb
|
42
|
+
- lib/app_mail/client.rb
|
43
|
+
- lib/app_mail/config.rb
|
44
|
+
- lib/app_mail/error.rb
|
45
|
+
- lib/app_mail/header_set.rb
|
46
|
+
- lib/app_mail/message.rb
|
47
|
+
- lib/app_mail/message_scope.rb
|
48
|
+
- lib/app_mail/send_message.rb
|
49
|
+
- lib/app_mail/send_result.rb
|
50
|
+
- lib/app_mail/version.rb
|
51
|
+
- lib/appmail.rb
|
52
|
+
homepage: https://appmail.io
|
53
|
+
licenses:
|
54
|
+
- MIT
|
55
|
+
metadata: {}
|
56
|
+
post_install_message:
|
57
|
+
rdoc_options: []
|
58
|
+
require_paths:
|
59
|
+
- lib
|
60
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
61
|
+
requirements:
|
62
|
+
- - ">="
|
63
|
+
- !ruby/object:Gem::Version
|
64
|
+
version: '0'
|
65
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
66
|
+
requirements:
|
67
|
+
- - ">="
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: '0'
|
70
|
+
requirements: []
|
71
|
+
rubyforge_project:
|
72
|
+
rubygems_version: 2.5.1
|
73
|
+
signing_key:
|
74
|
+
specification_version: 4
|
75
|
+
summary: Ruby library for the AppMail E-Mail Platform
|
76
|
+
test_files: []
|