ez-email 0.2.2 → 0.4.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 +4 -4
- checksums.yaml.gz.sig +0 -0
- data/CHANGES.md +6 -0
- data/Gemfile +3 -0
- data/MANIFEST.md +2 -1
- data/README.md +64 -15
- data/Rakefile +18 -8
- data/docker-compose.yml +9 -0
- data/ez-email.gemspec +18 -10
- data/lib/ez/email.rb +108 -22
- data/lib/ez-email.rb +2 -0
- data/spec/ez_email_spec.rb +197 -0
- data/test_attachments.rb +45 -0
- data.tar.gz.sig +0 -0
- metadata +75 -17
- metadata.gz.sig +0 -0
- data/test/test_ez_email.rb +0 -147
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ac9476958dae126c2767f7c6a70c970ffeae5eca5613590864c69be364931497
|
4
|
+
data.tar.gz: f722d3d6d4f5baf6eed6d79d9a9514f0cfdbe7b29a3e57c615895daada5854ba
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ba03fd9ede7a2e96bd6d8399d907357949e1c011d85cd0e56ddbd7dea3f8ba0e58a670b96c8caf2476d13405c6002ec4bb829f3cca4c946f8f7eb88f8260fff2
|
7
|
+
data.tar.gz: 0f4bf7d4fc3a76f3fa17a74c4866f25577a59240209d21d87bc5822e867c4b34aa3ddddb69c829fb47a5a4dadb7e14a11884dca31e38b7899757588abda03848
|
checksums.yaml.gz.sig
CHANGED
Binary file
|
data/CHANGES.md
CHANGED
data/Gemfile
ADDED
data/MANIFEST.md
CHANGED
data/README.md
CHANGED
@@ -1,44 +1,93 @@
|
|
1
1
|
### Description
|
2
|
-
|
2
|
+
A very easy interface for sending simple text based emails.
|
3
3
|
|
4
4
|
### Installation
|
5
|
-
|
5
|
+
`gem install ez-email`
|
6
|
+
|
7
|
+
### Adding the trusted cert
|
8
|
+
`gem cert --add <(curl -Ls https://raw.githubusercontent.com/djberg96/ez-email/main/certs/djberg96_pub.pem)`
|
6
9
|
|
7
10
|
### Synopsis
|
11
|
+
```ruby
|
12
|
+
require 'ez-email'
|
13
|
+
|
14
|
+
# Simple email
|
15
|
+
EZ::Email.deliver(
|
16
|
+
:to => 'your_friend@hotstuff.com',
|
17
|
+
:from => 'you@blah.com',
|
18
|
+
:subject => 'Hello',
|
19
|
+
:body => 'How are you?'
|
20
|
+
)
|
21
|
+
|
22
|
+
# Email with attachments
|
23
|
+
EZ::Email.deliver(
|
24
|
+
:to => 'your_friend@hotstuff.com',
|
25
|
+
:from => 'you@blah.com',
|
26
|
+
:subject => 'Files attached',
|
27
|
+
:body => 'Please find the attached files.',
|
28
|
+
:attachments => ['/path/to/file1.pdf', '/path/to/file2.txt']
|
29
|
+
)
|
8
30
|
```
|
9
|
-
|
10
|
-
|
11
|
-
EZ::Email.deliver(
|
12
|
-
:to => 'your_friend@hotstuff.com',
|
13
|
-
:from => 'you@blah.com',
|
14
|
-
:subject => 'Hello',
|
15
|
-
:body => 'How are you?'
|
16
|
-
)
|
17
|
-
```
|
18
|
-
|
31
|
+
|
19
32
|
### Rationale
|
20
33
|
|
21
34
|
When I originally created this library the existing list of email handling
|
22
35
|
libraries were either not designed for sending email, were extremely cumbersome,
|
23
36
|
had lousy interfaces, or were no longer maintained.
|
24
|
-
|
37
|
+
|
25
38
|
I just wanted to send a flippin' email! This library scratched that itch.
|
26
39
|
Hopefully you will find its simplicity useful, too.
|
27
40
|
|
41
|
+
### Features
|
42
|
+
|
43
|
+
* Simple interface for sending text emails
|
44
|
+
* Support for multiple recipients
|
45
|
+
* File attachments support
|
46
|
+
* Automatic MIME type detection for attachments
|
47
|
+
* Minimal dependencies
|
48
|
+
|
49
|
+
### API
|
50
|
+
|
51
|
+
The library supports these options:
|
52
|
+
|
53
|
+
* `:to` - Email address(es) of recipient(s). Can be a string or array. (Required)
|
54
|
+
* `:from` - Email address of sender. Defaults to user@hostname if not specified.
|
55
|
+
* `:subject` - Subject line of the email. (Required)
|
56
|
+
* `:body` - Body text of the email. (Required)
|
57
|
+
* `:attachments` - Array of file paths to attach. (Optional)
|
58
|
+
|
59
|
+
All file attachments are automatically base64 encoded and sent with appropriate MIME types.
|
60
|
+
|
61
|
+
### Local Testing
|
62
|
+
To run the specs you will need a mail server running locally. If you do not
|
63
|
+
already have a mail server running on port 1025 then install docker and run
|
64
|
+
the following command:
|
65
|
+
|
66
|
+
`docker compose run mailhog`
|
67
|
+
|
68
|
+
Once the mailhog docker image is installed and a container is running, you
|
69
|
+
can run the specs. You can also view the emails that were generated by pointing
|
70
|
+
your web browser at http://localhost:8025 after running the specs for visual
|
71
|
+
verification.
|
72
|
+
|
28
73
|
### Bugs
|
29
74
|
|
30
75
|
None that I'm aware of. Please log any bug reports on the project page at
|
31
76
|
|
32
77
|
https://github.com/djberg96/ez-email.
|
33
78
|
|
79
|
+
### See Also
|
80
|
+
|
81
|
+
The "pony" gem at https://github.com/benprew/pony.
|
82
|
+
|
34
83
|
### License
|
35
84
|
|
36
85
|
Apache-2.0
|
37
86
|
|
38
87
|
### Copyright
|
39
88
|
|
40
|
-
(C) 2009-
|
41
|
-
|
89
|
+
(C) 2009-2023, Daniel J. Berger, All Rights Reserved
|
90
|
+
|
42
91
|
### Author
|
43
92
|
|
44
93
|
Daniel Berger
|
data/Rakefile
CHANGED
@@ -1,16 +1,16 @@
|
|
1
1
|
require 'rake'
|
2
2
|
require 'rake/clean'
|
3
|
-
require '
|
3
|
+
require 'rspec/core/rake_task'
|
4
4
|
|
5
|
-
CLEAN.include("**/*.gem", "**/*.rbc")
|
5
|
+
CLEAN.include("**/*.gem", "**/*.rbc", "**/*.lock")
|
6
6
|
|
7
7
|
namespace :gem do
|
8
8
|
desc 'Build the ez-email gem'
|
9
9
|
task :create => [:clean] do
|
10
10
|
require 'rubygems/package'
|
11
|
-
spec =
|
11
|
+
spec = Gem::Specification.load('ez-email.gemspec')
|
12
12
|
spec.signing_key = File.join(Dir.home, '.ssh', 'gem-private_key.pem')
|
13
|
-
Gem::Package.build(spec
|
13
|
+
Gem::Package.build(spec)
|
14
14
|
end
|
15
15
|
|
16
16
|
desc "Install the ez-email package as a gem"
|
@@ -20,9 +20,19 @@ namespace :gem do
|
|
20
20
|
end
|
21
21
|
end
|
22
22
|
|
23
|
-
|
24
|
-
|
25
|
-
|
23
|
+
namespace :mailhog do
|
24
|
+
desc 'Start a local mailhog server'
|
25
|
+
task :start do
|
26
|
+
system('docker compose up -d')
|
27
|
+
end
|
28
|
+
|
29
|
+
desc 'Stop the local mail server'
|
30
|
+
task :stop do
|
31
|
+
system('docker compose down')
|
32
|
+
end
|
26
33
|
end
|
27
34
|
|
28
|
-
|
35
|
+
desc "Run the test suite"
|
36
|
+
RSpec::Core::RakeTask.new(:spec)
|
37
|
+
|
38
|
+
task :default => :spec
|
data/docker-compose.yml
ADDED
data/ez-email.gemspec
CHANGED
@@ -2,27 +2,35 @@ require 'rubygems'
|
|
2
2
|
|
3
3
|
Gem::Specification.new do |spec|
|
4
4
|
spec.name = 'ez-email'
|
5
|
-
spec.version = '0.
|
5
|
+
spec.version = '0.4.0'
|
6
6
|
spec.license = 'Apache-2.0'
|
7
7
|
spec.summary = 'Really easy emails'
|
8
8
|
spec.description = 'A very simple interface for sending email'
|
9
9
|
spec.author = 'Daniel Berger'
|
10
10
|
spec.email = 'djberg96@gmail.com'
|
11
11
|
spec.homepage = 'https://github.com/djberg96/ez-email'
|
12
|
-
spec.test_file = '
|
12
|
+
spec.test_file = 'spec/ez_email_spec.rb'
|
13
13
|
spec.files = Dir['**/*'].reject{ |f| f.include?('git') }
|
14
14
|
spec.cert_chain = Dir['certs/*']
|
15
|
-
|
15
|
+
|
16
16
|
spec.extra_rdoc_files = ['README.md', 'CHANGES.md', 'MANIFEST.md']
|
17
17
|
|
18
|
-
spec.add_development_dependency('
|
18
|
+
spec.add_development_dependency('rake')
|
19
|
+
spec.add_development_dependency('rspec', '~> 3.9')
|
20
|
+
|
21
|
+
spec.add_runtime_dependency('mime-types', '~> 3.0')
|
22
|
+
spec.add_runtime_dependency('net-smtp')
|
23
|
+
spec.add_runtime_dependency('base64')
|
19
24
|
|
20
25
|
spec.metadata = {
|
21
|
-
'homepage_uri'
|
22
|
-
'bug_tracker_uri'
|
23
|
-
'changelog_uri'
|
24
|
-
'documentation_uri'
|
25
|
-
'source_code_uri'
|
26
|
-
'wiki_uri'
|
26
|
+
'homepage_uri' => 'https://github.com/djberg96/ez-email',
|
27
|
+
'bug_tracker_uri' => 'https://github.com/djberg96/ez-email/issues',
|
28
|
+
'changelog_uri' => 'https://github.com/djberg96/ez-email/blob/main/CHANGES.md',
|
29
|
+
'documentation_uri' => 'https://github.com/djberg96/ez-email/wiki',
|
30
|
+
'source_code_uri' => 'https://github.com/djberg96/ez-email',
|
31
|
+
'wiki_uri' => 'https://github.com/djberg96/ez-email/wiki',
|
32
|
+
'github_repo' => 'https://github.com/djberg96/ez-email',
|
33
|
+
'funding_uri' => 'https://github.com/sponsors/djberg96',
|
34
|
+
'rubygems_mfa_required' => 'true'
|
27
35
|
}
|
28
36
|
end
|
data/lib/ez/email.rb
CHANGED
@@ -1,19 +1,25 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'resolv'
|
2
4
|
require 'etc'
|
3
5
|
require 'socket'
|
4
6
|
require 'net/smtp'
|
7
|
+
require 'base64'
|
8
|
+
require 'mime/types'
|
5
9
|
|
6
10
|
# The EZ module serves as a namespace only.
|
7
11
|
module EZ
|
8
|
-
|
9
12
|
# The Email class encapsulates certain SMTP attributes, which are then
|
10
13
|
# used to send simple emails.
|
11
14
|
class Email
|
12
15
|
# The version of the ez-email library
|
13
|
-
VERSION = '0.
|
16
|
+
VERSION = '0.4.0'
|
14
17
|
|
15
18
|
class << self
|
19
|
+
# Writer method for the mail_host property.
|
16
20
|
attr_writer :mail_host
|
21
|
+
|
22
|
+
# Writer method for the mail_port property.
|
17
23
|
attr_writer :mail_port
|
18
24
|
|
19
25
|
# The name of the mail host to use when sending email. The default
|
@@ -48,12 +54,16 @@ module EZ
|
|
48
54
|
# The body of the email. Mandatory.
|
49
55
|
attr_accessor :body
|
50
56
|
|
57
|
+
# An array of file paths to attach to the email. Optional.
|
58
|
+
attr_accessor :attachments
|
59
|
+
|
51
60
|
# Creates a new EZ::Email object. As a general rule you won't use
|
52
61
|
# this method, but should use EZ::Email.deliver instead.
|
53
62
|
#
|
54
|
-
def initialize(options={})
|
63
|
+
def initialize(options = {})
|
55
64
|
raise TypeError unless options.is_a?(Hash)
|
56
|
-
options[:from] ||= Etc.getlogin
|
65
|
+
options[:from] ||= "#{Etc.getlogin}@#{Socket.gethostname}"
|
66
|
+
@attachments = []
|
57
67
|
validate_options(options)
|
58
68
|
@options = options
|
59
69
|
end
|
@@ -66,25 +76,55 @@ module EZ
|
|
66
76
|
host = EZ::Email.mail_host
|
67
77
|
port = EZ::Email.mail_port
|
68
78
|
|
69
|
-
to_list =
|
70
|
-
|
71
|
-
Net::SMTP.start(host, port, host)
|
72
|
-
smtp.open_message_stream(
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
79
|
+
to_list = to.is_a?(Array) ? to : [to]
|
80
|
+
|
81
|
+
Net::SMTP.start(host, port, host) do |smtp|
|
82
|
+
smtp.open_message_stream(from, to) do |stream|
|
83
|
+
if attachments.empty?
|
84
|
+
# Simple email without attachments
|
85
|
+
stream.puts "From: #{from}"
|
86
|
+
stream.puts "To: #{to_list.join(', ')}"
|
87
|
+
stream.puts "Subject: #{subject}"
|
88
|
+
stream.puts
|
89
|
+
stream.puts body
|
90
|
+
else
|
91
|
+
# Email with attachments - use multipart MIME
|
92
|
+
boundary = generate_boundary
|
93
|
+
|
94
|
+
stream.puts "From: #{from}"
|
95
|
+
stream.puts "To: #{to_list.join(', ')}"
|
96
|
+
stream.puts "Subject: #{subject}"
|
97
|
+
stream.puts "MIME-Version: 1.0"
|
98
|
+
stream.puts "Content-Type: multipart/mixed; boundary=\"#{boundary}\""
|
99
|
+
stream.puts
|
100
|
+
|
101
|
+
# Text body part
|
102
|
+
stream.puts "--#{boundary}"
|
103
|
+
stream.puts "Content-Type: text/plain; charset=UTF-8"
|
104
|
+
stream.puts "Content-Transfer-Encoding: 7bit"
|
105
|
+
stream.puts
|
106
|
+
stream.puts body
|
107
|
+
stream.puts
|
108
|
+
|
109
|
+
# Attachment parts
|
110
|
+
attachments.each do |file_path|
|
111
|
+
add_attachment(stream, file_path, boundary)
|
112
|
+
end
|
113
|
+
|
114
|
+
# End boundary
|
115
|
+
stream.puts "--#{boundary}--"
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
80
119
|
end
|
81
120
|
|
82
|
-
# Delivers a simple text email message using
|
121
|
+
# Delivers a simple text email message using these options:
|
83
122
|
#
|
84
123
|
# * to
|
85
124
|
# * from
|
86
125
|
# * subject
|
87
126
|
# * body
|
127
|
+
# * attachments (optional)
|
88
128
|
#
|
89
129
|
# Examples:
|
90
130
|
#
|
@@ -104,6 +144,15 @@ module EZ
|
|
104
144
|
# :body => 'How are you?'
|
105
145
|
# )
|
106
146
|
#
|
147
|
+
# # Send an email with attachments
|
148
|
+
# EZ::Email.deliver(
|
149
|
+
# :to => 'someone@example.com',
|
150
|
+
# :from => 'me@example.com',
|
151
|
+
# :subject => 'Files attached',
|
152
|
+
# :body => 'Please find the attached files.',
|
153
|
+
# :attachments => ['/path/to/file1.pdf', '/path/to/file2.txt']
|
154
|
+
# )
|
155
|
+
#
|
107
156
|
# This is a shortcut for EZ::Email.new + EZ::Email#deliver.
|
108
157
|
#
|
109
158
|
def self.deliver(options)
|
@@ -116,17 +165,54 @@ module EZ
|
|
116
165
|
# the attribute values.
|
117
166
|
#
|
118
167
|
def validate_options(hash)
|
119
|
-
valid = %w[to from subject body]
|
168
|
+
valid = %w[to from subject body attachments]
|
120
169
|
|
121
|
-
hash.each
|
170
|
+
hash.each do |key, value|
|
122
171
|
key = key.to_s.downcase
|
123
172
|
raise ArgumentError unless valid.include?(key)
|
124
|
-
send("#{key}=", value)
|
125
|
-
}
|
126
173
|
|
127
|
-
|
128
|
-
|
174
|
+
if key == 'attachments'
|
175
|
+
# Validate attachments
|
176
|
+
attachments_value = value.is_a?(Array) ? value : [value]
|
177
|
+
attachments_value.each do |file_path|
|
178
|
+
raise ArgumentError, "Attachment file not found: #{file_path}" unless File.exist?(file_path)
|
179
|
+
raise ArgumentError, "Attachment is not a file: #{file_path}" unless File.file?(file_path)
|
180
|
+
end
|
181
|
+
self.attachments = attachments_value
|
182
|
+
else
|
183
|
+
send("#{key}=", value)
|
184
|
+
end
|
129
185
|
end
|
186
|
+
|
187
|
+
raise ArgumentError, 'Missing :to' if to.nil?
|
188
|
+
raise ArgumentError, 'Missing :subject' if subject.nil?
|
189
|
+
raise ArgumentError, 'Missing :body' if body.nil?
|
190
|
+
end
|
191
|
+
|
192
|
+
# Generate a unique boundary for multipart MIME messages
|
193
|
+
def generate_boundary
|
194
|
+
"----=_NextPart_#{Time.now.to_i}_#{rand(1000000)}"
|
195
|
+
end
|
196
|
+
|
197
|
+
# Add an attachment to the email stream
|
198
|
+
def add_attachment(stream, file_path, boundary)
|
199
|
+
filename = File.basename(file_path)
|
200
|
+
|
201
|
+
# Determine MIME type
|
202
|
+
mime_type = MIME::Types.type_for(file_path).first
|
203
|
+
content_type = mime_type ? mime_type.content_type : 'application/octet-stream'
|
204
|
+
|
205
|
+
stream.puts "--#{boundary}"
|
206
|
+
stream.puts "Content-Type: #{content_type}; name=\"#{filename}\""
|
207
|
+
stream.puts "Content-Transfer-Encoding: base64"
|
208
|
+
stream.puts "Content-Disposition: attachment; filename=\"#{filename}\""
|
209
|
+
stream.puts
|
210
|
+
|
211
|
+
# Read file and encode as base64
|
212
|
+
file_content = File.read(file_path)
|
213
|
+
encoded_content = Base64.encode64(file_content)
|
214
|
+
stream.puts encoded_content
|
215
|
+
stream.puts
|
130
216
|
end
|
131
217
|
end
|
132
218
|
end
|
data/lib/ez-email.rb
CHANGED
@@ -0,0 +1,197 @@
|
|
1
|
+
########################################################################
|
2
|
+
# ez_email_spec.rb
|
3
|
+
#
|
4
|
+
# Specs for the EZ::Email library. These specs assume that you are
|
5
|
+
# running the mailhog docker container on port 1025.
|
6
|
+
#
|
7
|
+
# Install docker and run "docker compose run mailhog" first.
|
8
|
+
########################################################################
|
9
|
+
require 'rspec'
|
10
|
+
require 'ez/email'
|
11
|
+
require 'socket'
|
12
|
+
require 'etc'
|
13
|
+
|
14
|
+
RSpec.describe EZ::Email do
|
15
|
+
let(:host){ Socket.gethostname }
|
16
|
+
let(:login){ Etc.getlogin }
|
17
|
+
let(:port){ 1025 }
|
18
|
+
|
19
|
+
before do
|
20
|
+
@to = 'foo@some_mail_service.com'
|
21
|
+
@from = 'bar@some_mail_service.com'
|
22
|
+
@subj = 'This is a test'
|
23
|
+
@body = 'How are you?'
|
24
|
+
|
25
|
+
@opts = {:to => @to, :from => @from, :subject => @subj, :body => @body }
|
26
|
+
@email = EZ::Email.new(@opts)
|
27
|
+
end
|
28
|
+
|
29
|
+
example "version is set to expected value" do
|
30
|
+
expect(EZ::Email::VERSION).to eq('0.4.0')
|
31
|
+
expect(EZ::Email::VERSION).to be_frozen
|
32
|
+
end
|
33
|
+
|
34
|
+
example "to getter method basic functionality" do
|
35
|
+
expect(@email).to respond_to(:to)
|
36
|
+
expect{ @email.to }.not_to raise_error
|
37
|
+
expect(@email.to).not_to be_nil
|
38
|
+
end
|
39
|
+
|
40
|
+
example "to getter method returns expected value" do
|
41
|
+
expect(@email.to).to eq(@to)
|
42
|
+
end
|
43
|
+
|
44
|
+
example "to setter method basic functionality" do
|
45
|
+
expect(@email).to respond_to(:to=)
|
46
|
+
expect{ @email.to = 'bogus@some_bogus.com' }.not_to raise_error
|
47
|
+
end
|
48
|
+
|
49
|
+
example "to setter actually sets value" do
|
50
|
+
@email.to = 'bogus@some_bogus.com'
|
51
|
+
expect('bogus@some_bogus.com').to eq(@email.to)
|
52
|
+
end
|
53
|
+
|
54
|
+
example "from getter basic functionality" do
|
55
|
+
expect(@email).to respond_to(:from)
|
56
|
+
expect{ @email.from }.not_to raise_error
|
57
|
+
expect(@email.from).not_to be_nil
|
58
|
+
end
|
59
|
+
|
60
|
+
example "from setter basic functionality" do
|
61
|
+
expect(@email).to respond_to(:from=)
|
62
|
+
expect{ @email.from = 'bogus@some_bogus.com' }.not_to raise_error
|
63
|
+
end
|
64
|
+
|
65
|
+
example "from method returns expected value" do
|
66
|
+
expect(@email.from).to eq(@from)
|
67
|
+
end
|
68
|
+
|
69
|
+
example "from defaults to username@host if not set in constructor" do
|
70
|
+
@email = EZ::Email.new(:to => 'x', :subject => 'x', :body => 'x')
|
71
|
+
expected = login << '@' << host
|
72
|
+
expect(@email.from).to eq(expected)
|
73
|
+
end
|
74
|
+
|
75
|
+
example "subject getter basic functionality" do
|
76
|
+
expect(@email).to respond_to(:subject)
|
77
|
+
expect{ @email.subject }.not_to raise_error
|
78
|
+
expect(@email.subject).not_to be_nil
|
79
|
+
end
|
80
|
+
|
81
|
+
example "subject setter basic functionality" do
|
82
|
+
expect(@email).to respond_to(:subject=)
|
83
|
+
expect{ @email.subject = 'bogus@bogus.com' }.not_to raise_error
|
84
|
+
end
|
85
|
+
|
86
|
+
example "subject method returns expected value" do
|
87
|
+
expect(@email.subject).to eq(@subj)
|
88
|
+
end
|
89
|
+
|
90
|
+
example "body getter basic functionality" do
|
91
|
+
expect(@email).to respond_to(:body)
|
92
|
+
expect{ @email.body }.not_to raise_error
|
93
|
+
expect(@email.body).not_to be_nil
|
94
|
+
end
|
95
|
+
|
96
|
+
example "body setter basic functionality" do
|
97
|
+
expect(@email).to respond_to(:body=)
|
98
|
+
expect{ @email.body = "Test" }.not_to raise_error
|
99
|
+
end
|
100
|
+
|
101
|
+
example "body method returns the expected value" do
|
102
|
+
expect(@email.body).to eq(@body)
|
103
|
+
end
|
104
|
+
|
105
|
+
example "mail_host getter basic functionality" do
|
106
|
+
expect(EZ::Email).to respond_to(:mail_host)
|
107
|
+
expect{ EZ::Email.mail_host }.not_to raise_error
|
108
|
+
expect(EZ::Email.mail_host).not_to be_nil
|
109
|
+
end
|
110
|
+
|
111
|
+
example "mail_host setter basic functionality" do
|
112
|
+
expect(EZ::Email).to respond_to(:mail_host=)
|
113
|
+
expect{ EZ::Email.mail_host = 'Test' }.not_to raise_error
|
114
|
+
expect(EZ::Email.mail_host).to eq('Test')
|
115
|
+
end
|
116
|
+
|
117
|
+
example "mail_port singleton getter basic functionality" do
|
118
|
+
expect(EZ::Email).to respond_to(:mail_port)
|
119
|
+
end
|
120
|
+
|
121
|
+
example "mail_port method returns the expected default value" do
|
122
|
+
expect(EZ::Email.mail_port).to eq(25)
|
123
|
+
end
|
124
|
+
|
125
|
+
example "mail_port singleton setter basic functionality" do
|
126
|
+
expect(EZ::Email).to respond_to(:mail_port=)
|
127
|
+
expect{ EZ::Email.mail_port = port }.not_to raise_error
|
128
|
+
expect(EZ::Email.mail_port).to eq(1025)
|
129
|
+
end
|
130
|
+
|
131
|
+
example "deliver singleton method basic functionality" do
|
132
|
+
expect(EZ::Email).to respond_to(:deliver)
|
133
|
+
end
|
134
|
+
|
135
|
+
example "deliver singleton method works without error" do
|
136
|
+
EZ::Email.mail_host = 'localhost'
|
137
|
+
EZ::Email.mail_port = port
|
138
|
+
expect{ EZ::Email.deliver(@opts) }.not_to raise_error
|
139
|
+
end
|
140
|
+
|
141
|
+
example "passing an invalid option to the constructor raises an error" do
|
142
|
+
expect{ EZ::Email.send(:new, {:bogus => 77}) }.to raise_error(ArgumentError)
|
143
|
+
end
|
144
|
+
|
145
|
+
example "attachments getter basic functionality" do
|
146
|
+
expect(@email).to respond_to(:attachments)
|
147
|
+
expect{ @email.attachments }.not_to raise_error
|
148
|
+
end
|
149
|
+
|
150
|
+
example "attachments setter basic functionality" do
|
151
|
+
expect(@email).to respond_to(:attachments=)
|
152
|
+
expect{ @email.attachments = [] }.not_to raise_error
|
153
|
+
end
|
154
|
+
|
155
|
+
example "attachments method returns an array" do
|
156
|
+
expect(@email.attachments).to be_an(Array)
|
157
|
+
end
|
158
|
+
|
159
|
+
example "attachments defaults to empty array" do
|
160
|
+
expect(@email.attachments).to be_empty
|
161
|
+
end
|
162
|
+
|
163
|
+
example "can set attachments via constructor" do
|
164
|
+
# Create a test file
|
165
|
+
test_file = '/tmp/test_attachment.txt'
|
166
|
+
File.write(test_file, 'test content')
|
167
|
+
|
168
|
+
begin
|
169
|
+
opts_with_attachments = @opts.merge(attachments: [test_file])
|
170
|
+
email = EZ::Email.new(opts_with_attachments)
|
171
|
+
expect(email.attachments).to eq([test_file])
|
172
|
+
ensure
|
173
|
+
File.delete(test_file) if File.exist?(test_file)
|
174
|
+
end
|
175
|
+
end
|
176
|
+
|
177
|
+
example "raises error for non-existent attachment file" do
|
178
|
+
opts_with_bad_attachment = @opts.merge(attachments: ['/non/existent/file.txt'])
|
179
|
+
expect{ EZ::Email.new(opts_with_bad_attachment) }.to raise_error(ArgumentError, /Attachment file not found/)
|
180
|
+
end
|
181
|
+
|
182
|
+
example "can deliver email with attachments" do
|
183
|
+
# Create a test file
|
184
|
+
test_file = '/tmp/test_attachment.txt'
|
185
|
+
File.write(test_file, 'test content for attachment')
|
186
|
+
|
187
|
+
begin
|
188
|
+
EZ::Email.mail_host = 'localhost'
|
189
|
+
EZ::Email.mail_port = port
|
190
|
+
|
191
|
+
opts_with_attachments = @opts.merge(attachments: [test_file])
|
192
|
+
expect{ EZ::Email.deliver(opts_with_attachments) }.not_to raise_error
|
193
|
+
ensure
|
194
|
+
File.delete(test_file) if File.exist?(test_file)
|
195
|
+
end
|
196
|
+
end
|
197
|
+
end
|
data/test_attachments.rb
ADDED
@@ -0,0 +1,45 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require_relative 'lib/ez-email'
|
4
|
+
|
5
|
+
# Create a test file for attachment
|
6
|
+
test_file = '/tmp/sample_attachment.txt'
|
7
|
+
File.write(test_file, "This is a sample attachment file.\nIt contains some test content.")
|
8
|
+
|
9
|
+
begin
|
10
|
+
# Create an email with attachment
|
11
|
+
email = EZ::Email.new(
|
12
|
+
to: 'recipient@example.com',
|
13
|
+
from: 'sender@example.com',
|
14
|
+
subject: 'Test Email with Attachment',
|
15
|
+
body: 'Hello! Please find the attached file.',
|
16
|
+
attachments: [test_file]
|
17
|
+
)
|
18
|
+
|
19
|
+
puts "Email created successfully with attachment: #{test_file}"
|
20
|
+
puts "Attachments: #{email.attachments}"
|
21
|
+
puts "To: #{email.to}"
|
22
|
+
puts "From: #{email.from}"
|
23
|
+
puts "Subject: #{email.subject}"
|
24
|
+
puts "Body: #{email.body}"
|
25
|
+
|
26
|
+
# You can also use the class method
|
27
|
+
puts "\nUsing class method:"
|
28
|
+
|
29
|
+
# This would deliver if you had a mail server running
|
30
|
+
# EZ::Email.deliver(
|
31
|
+
# to: 'recipient@example.com',
|
32
|
+
# from: 'sender@example.com',
|
33
|
+
# subject: 'Test Email with Multiple Attachments',
|
34
|
+
# body: 'Hello! Please find the attached files.',
|
35
|
+
# attachments: [test_file, '/path/to/another/file.pdf']
|
36
|
+
# )
|
37
|
+
|
38
|
+
puts "All tests passed! Attachment functionality is working."
|
39
|
+
|
40
|
+
rescue => e
|
41
|
+
puts "Error: #{e.message}"
|
42
|
+
ensure
|
43
|
+
# Clean up
|
44
|
+
File.delete(test_file) if File.exist?(test_file)
|
45
|
+
end
|
data.tar.gz.sig
CHANGED
Binary file
|
metadata
CHANGED
@@ -1,11 +1,11 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ez-email
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Daniel Berger
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain:
|
11
11
|
- |
|
@@ -35,10 +35,10 @@ cert_chain:
|
|
35
35
|
ORVCZpRuCPpmC8qmqxUnARDArzucjaclkxjLWvCVHeFa9UP7K3Nl9oTjJNv+7/jM
|
36
36
|
WZs4eecIcUc4tKdHxcAJ0MO/Dkqq7hGaiHpwKY76wQ1+8xAh
|
37
37
|
-----END CERTIFICATE-----
|
38
|
-
date:
|
38
|
+
date: 2025-07-13 00:00:00.000000000 Z
|
39
39
|
dependencies:
|
40
40
|
- !ruby/object:Gem::Dependency
|
41
|
-
name:
|
41
|
+
name: rake
|
42
42
|
requirement: !ruby/object:Gem::Requirement
|
43
43
|
requirements:
|
44
44
|
- - ">="
|
@@ -51,6 +51,62 @@ dependencies:
|
|
51
51
|
- - ">="
|
52
52
|
- !ruby/object:Gem::Version
|
53
53
|
version: '0'
|
54
|
+
- !ruby/object:Gem::Dependency
|
55
|
+
name: rspec
|
56
|
+
requirement: !ruby/object:Gem::Requirement
|
57
|
+
requirements:
|
58
|
+
- - "~>"
|
59
|
+
- !ruby/object:Gem::Version
|
60
|
+
version: '3.9'
|
61
|
+
type: :development
|
62
|
+
prerelease: false
|
63
|
+
version_requirements: !ruby/object:Gem::Requirement
|
64
|
+
requirements:
|
65
|
+
- - "~>"
|
66
|
+
- !ruby/object:Gem::Version
|
67
|
+
version: '3.9'
|
68
|
+
- !ruby/object:Gem::Dependency
|
69
|
+
name: mime-types
|
70
|
+
requirement: !ruby/object:Gem::Requirement
|
71
|
+
requirements:
|
72
|
+
- - "~>"
|
73
|
+
- !ruby/object:Gem::Version
|
74
|
+
version: '3.0'
|
75
|
+
type: :runtime
|
76
|
+
prerelease: false
|
77
|
+
version_requirements: !ruby/object:Gem::Requirement
|
78
|
+
requirements:
|
79
|
+
- - "~>"
|
80
|
+
- !ruby/object:Gem::Version
|
81
|
+
version: '3.0'
|
82
|
+
- !ruby/object:Gem::Dependency
|
83
|
+
name: net-smtp
|
84
|
+
requirement: !ruby/object:Gem::Requirement
|
85
|
+
requirements:
|
86
|
+
- - ">="
|
87
|
+
- !ruby/object:Gem::Version
|
88
|
+
version: '0'
|
89
|
+
type: :runtime
|
90
|
+
prerelease: false
|
91
|
+
version_requirements: !ruby/object:Gem::Requirement
|
92
|
+
requirements:
|
93
|
+
- - ">="
|
94
|
+
- !ruby/object:Gem::Version
|
95
|
+
version: '0'
|
96
|
+
- !ruby/object:Gem::Dependency
|
97
|
+
name: base64
|
98
|
+
requirement: !ruby/object:Gem::Requirement
|
99
|
+
requirements:
|
100
|
+
- - ">="
|
101
|
+
- !ruby/object:Gem::Version
|
102
|
+
version: '0'
|
103
|
+
type: :runtime
|
104
|
+
prerelease: false
|
105
|
+
version_requirements: !ruby/object:Gem::Requirement
|
106
|
+
requirements:
|
107
|
+
- - ">="
|
108
|
+
- !ruby/object:Gem::Version
|
109
|
+
version: '0'
|
54
110
|
description: A very simple interface for sending email
|
55
111
|
email: djberg96@gmail.com
|
56
112
|
executables: []
|
@@ -60,31 +116,33 @@ extra_rdoc_files:
|
|
60
116
|
- CHANGES.md
|
61
117
|
- MANIFEST.md
|
62
118
|
files:
|
119
|
+
- CHANGES.md
|
120
|
+
- Gemfile
|
63
121
|
- LICENSE
|
64
|
-
-
|
65
|
-
- test/test_ez_email.rb
|
66
|
-
- ez-email.gemspec
|
122
|
+
- MANIFEST.md
|
67
123
|
- README.md
|
68
124
|
- Rakefile
|
69
|
-
- MANIFEST.md
|
70
|
-
- certs
|
71
125
|
- certs/djberg96_pub.pem
|
72
|
-
-
|
126
|
+
- docker-compose.yml
|
127
|
+
- ez-email.gemspec
|
73
128
|
- lib/ez-email.rb
|
74
|
-
- lib/ez
|
75
129
|
- lib/ez/email.rb
|
76
|
-
-
|
130
|
+
- spec/ez_email_spec.rb
|
131
|
+
- test_attachments.rb
|
77
132
|
homepage: https://github.com/djberg96/ez-email
|
78
133
|
licenses:
|
79
134
|
- Apache-2.0
|
80
135
|
metadata:
|
81
136
|
homepage_uri: https://github.com/djberg96/ez-email
|
82
137
|
bug_tracker_uri: https://github.com/djberg96/ez-email/issues
|
83
|
-
changelog_uri: https://github.com/djberg96/ez-email/blob/
|
138
|
+
changelog_uri: https://github.com/djberg96/ez-email/blob/main/CHANGES.md
|
84
139
|
documentation_uri: https://github.com/djberg96/ez-email/wiki
|
85
140
|
source_code_uri: https://github.com/djberg96/ez-email
|
86
141
|
wiki_uri: https://github.com/djberg96/ez-email/wiki
|
87
|
-
|
142
|
+
github_repo: https://github.com/djberg96/ez-email
|
143
|
+
funding_uri: https://github.com/sponsors/djberg96
|
144
|
+
rubygems_mfa_required: 'true'
|
145
|
+
post_install_message:
|
88
146
|
rdoc_options: []
|
89
147
|
require_paths:
|
90
148
|
- lib
|
@@ -99,9 +157,9 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
99
157
|
- !ruby/object:Gem::Version
|
100
158
|
version: '0'
|
101
159
|
requirements: []
|
102
|
-
rubygems_version: 3.
|
103
|
-
signing_key:
|
160
|
+
rubygems_version: 3.5.22
|
161
|
+
signing_key:
|
104
162
|
specification_version: 4
|
105
163
|
summary: Really easy emails
|
106
164
|
test_files:
|
107
|
-
-
|
165
|
+
- spec/ez_email_spec.rb
|
metadata.gz.sig
CHANGED
Binary file
|
data/test/test_ez_email.rb
DELETED
@@ -1,147 +0,0 @@
|
|
1
|
-
########################################################################
|
2
|
-
# test_ez_email.rb
|
3
|
-
#
|
4
|
-
# Test suite for the EZ::Email library.
|
5
|
-
########################################################################
|
6
|
-
require 'test-unit'
|
7
|
-
require 'ez/email'
|
8
|
-
require 'socket'
|
9
|
-
require 'etc'
|
10
|
-
|
11
|
-
class TC_EZ_Email < Test::Unit::TestCase
|
12
|
-
def self.startup
|
13
|
-
@@host = Socket.gethostname
|
14
|
-
@@login = Etc.getlogin
|
15
|
-
end
|
16
|
-
|
17
|
-
def setup
|
18
|
-
@to = 'foo@some_mail_service.com'
|
19
|
-
@from = 'bar@some_mail_service.com'
|
20
|
-
@subj = 'This is a test'
|
21
|
-
@body = 'How are you?'
|
22
|
-
|
23
|
-
@opts = {:to => @to, :from => @from, :subject => @subj, :body => @body }
|
24
|
-
@email = EZ::Email.new(@opts)
|
25
|
-
end
|
26
|
-
|
27
|
-
test "version is set to expected value" do
|
28
|
-
assert_equal('0.2.2', EZ::Email::VERSION)
|
29
|
-
assert_true(EZ::Email::VERSION.frozen?)
|
30
|
-
end
|
31
|
-
|
32
|
-
test "to getter method basic functionality" do
|
33
|
-
assert_respond_to(@email, :to)
|
34
|
-
assert_nothing_raised{ @email.to }
|
35
|
-
assert_not_nil(@email.to)
|
36
|
-
end
|
37
|
-
|
38
|
-
test "to getter method returns expected value" do
|
39
|
-
assert_equal(@to, @email.to)
|
40
|
-
end
|
41
|
-
|
42
|
-
test "to setter method basic functionality" do
|
43
|
-
assert_respond_to(@email, :to=)
|
44
|
-
assert_nothing_raised{ @email.to = 'bogus@some_bogus.com' }
|
45
|
-
end
|
46
|
-
|
47
|
-
test "to setter actually sets value" do
|
48
|
-
@email.to = 'bogus@some_bogus.com'
|
49
|
-
assert_equal(@email.to, 'bogus@some_bogus.com')
|
50
|
-
end
|
51
|
-
|
52
|
-
test "from getter basic functionality" do
|
53
|
-
assert_respond_to(@email, :from)
|
54
|
-
assert_nothing_raised{ @email.from }
|
55
|
-
assert_not_nil(@email.from)
|
56
|
-
end
|
57
|
-
|
58
|
-
test "from setter basic functionality" do
|
59
|
-
assert_respond_to(@email, :from=)
|
60
|
-
assert_nothing_raised{ @email.from = 'bogus@some_bogus.com' }
|
61
|
-
end
|
62
|
-
|
63
|
-
test "from method returns expected value" do
|
64
|
-
assert_equal(@from, @email.from)
|
65
|
-
end
|
66
|
-
|
67
|
-
test "from defaults to username@host if not set in constructor" do
|
68
|
-
@email = EZ::Email.new(:to => 'x', :subject => 'x', :body => 'x')
|
69
|
-
expected = @@login << '@' << @@host
|
70
|
-
assert_equal(expected, @email.from)
|
71
|
-
end
|
72
|
-
|
73
|
-
test "subject getter basic functionality" do
|
74
|
-
assert_respond_to(@email, :subject)
|
75
|
-
assert_nothing_raised{ @email.subject }
|
76
|
-
assert_not_nil(@email.subject)
|
77
|
-
end
|
78
|
-
|
79
|
-
test "subject setter basic functionality" do
|
80
|
-
assert_respond_to(@email, :subject=)
|
81
|
-
assert_nothing_raised{ @email.subject = 'bogus@bogus.com' }
|
82
|
-
end
|
83
|
-
|
84
|
-
test "subject method returns expected value" do
|
85
|
-
assert_equal(@subj, @email.subject)
|
86
|
-
end
|
87
|
-
|
88
|
-
test "body getter basic functionality" do
|
89
|
-
assert_respond_to(@email, :body)
|
90
|
-
assert_nothing_raised{ @email.body }
|
91
|
-
assert_not_nil(@email.body)
|
92
|
-
end
|
93
|
-
|
94
|
-
test "body setter basic functionality" do
|
95
|
-
assert_respond_to(@email, :body=)
|
96
|
-
assert_nothing_raised{ @email.body = "Test" }
|
97
|
-
end
|
98
|
-
|
99
|
-
test "body method returns the expected value" do
|
100
|
-
assert_equal(@body, @email.body)
|
101
|
-
end
|
102
|
-
|
103
|
-
test "mail_host getter basic functionality" do
|
104
|
-
assert_respond_to(EZ::Email, :mail_host)
|
105
|
-
assert_nothing_raised{ EZ::Email.mail_host }
|
106
|
-
assert_not_nil(EZ::Email.mail_host)
|
107
|
-
end
|
108
|
-
|
109
|
-
test "mail_host setter basic functionality" do
|
110
|
-
assert_respond_to(EZ::Email, :mail_host=)
|
111
|
-
assert_nothing_raised{ EZ::Email.mail_host = "Test" }
|
112
|
-
end
|
113
|
-
|
114
|
-
test "mail_port singleton getter basic functionality" do
|
115
|
-
assert_respond_to(EZ::Email, :mail_port)
|
116
|
-
end
|
117
|
-
|
118
|
-
test "mail_port singleton setter basic functionality" do
|
119
|
-
assert_respond_to(EZ::Email, :mail_port=)
|
120
|
-
end
|
121
|
-
|
122
|
-
test "mail_port method returns the expected value" do
|
123
|
-
assert_equal(25, EZ::Email.mail_port)
|
124
|
-
end
|
125
|
-
|
126
|
-
test "deliver singleton method basic functionality" do
|
127
|
-
assert_respond_to(EZ::Email, :deliver)
|
128
|
-
end
|
129
|
-
|
130
|
-
test "passing an invalid option to the constructor raises an error" do
|
131
|
-
assert_raise(ArgumentError){ EZ::Email.send(:new, {:bogus => 77}) }
|
132
|
-
end
|
133
|
-
|
134
|
-
def teardown
|
135
|
-
@to = nil
|
136
|
-
@from = nil
|
137
|
-
@subj = nil
|
138
|
-
@body = nil
|
139
|
-
@opts = nil
|
140
|
-
@email = nil
|
141
|
-
end
|
142
|
-
|
143
|
-
def self.shutdown
|
144
|
-
@@host = nil
|
145
|
-
@@login = nil
|
146
|
-
end
|
147
|
-
end
|