supermail 0.1.0 → 0.2.1

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 53951b27c057ea4419f1ffbbc3666189712d30449af65e539148d7df306de7d3
4
- data.tar.gz: 789c9f9844880bae6611b9c5cdb958a4fb6b2d7c59888db016c503ebabec3573
3
+ metadata.gz: 4efb804624582618a2d1330b68b48030e27a0764f82bd8e5a99d01ba955d2174
4
+ data.tar.gz: 362d37bf770583b50c86e26cd280158cb8885e8725589ec68a4093ed5fabe79a
5
5
  SHA512:
6
- metadata.gz: 4de9d3383587ea03cd2eb302c6db564d88972535f286ed3ed2181146a56cc815d893e2a84543435854f92f39b767598bd5cef348516865f6706d290961f38d27
7
- data.tar.gz: 6364025594980a3ca8776970cd20be025cbe044cc69dc55766f89e874842f691e0d2b244a0dba773f92976ca6d69ab28bc0956233d25195e1afbbed67723d956
6
+ metadata.gz: d3d68858b41c793e45eda60b43f557bd0fc3e049f248d22352f8bd2e52544b10d2b374befca84fac46de283807352e59e2dbd8bb1e8c605fa7826b2b70789935
7
+ data.tar.gz: 799eca08e4b0997fda627688b0707442cf5a2d66dc8c42fdf10bfcef6d7a1a2d6e2b4641c00de898ffc1e4dbd78b2af50bd58de8926b6ffbe520c76058f2dc8d
data/README.md CHANGED
@@ -1,6 +1,36 @@
1
1
  # Supermail
2
2
 
3
- Supermail is a slightly more intuitive way of organizing Emails in a Rails application.
3
+ Organize emails with plain 'ol Ruby objects in a Rails application, like this:
4
+
5
+ ```ruby
6
+ # ./app/email/user/welcome.rb
7
+ class User::WelcomeEmail < ApplicationEmail
8
+ def initialize(person:)
9
+ @person = person
10
+ end
11
+
12
+ def to = @person.email
13
+ def subject = "Welcome to Beautiful Ruby"
14
+ def body
15
+ super do
16
+ <<~_
17
+ Hi #{@person.name},
18
+
19
+ You're going to learn a ton at https://beautifulruby.com.
20
+ _
21
+ end
22
+ end
23
+ end
24
+ ```
25
+
26
+ Contrast that with rails ActionMailer, where you will spend 20 minutes trying to figure out how to send an email. I created this gem because I got tired of digging through Rails docs to understand how to intialize an email and send it. PORO's FTW!
27
+
28
+ ## Support this project
29
+
30
+ Learn how to build UI's out of Ruby classes and support this project by ordering the [Phlex on Rails video course](https://beautifulruby.com/phlex).
31
+
32
+ [![](https://immutable.terminalwire.com/hmM9jvv7yF89frBUfjikUfRmdUsTVZ8YvXc7OnnYoERXfLJLzDcj5dFM7qdfMG2bqQLuw633Zt1gl3O7z0zKmH6k8QmifN7z0kJo.png)](https://beautifulruby.com/phlex/forms/introduction)
33
+
4
34
 
5
35
  ## Installation
6
36
 
@@ -16,22 +46,21 @@ Then install it in Rails.
16
46
  rails generate supermail:install
17
47
  ```
18
48
 
19
- This creates the `app/emails/application_email.rb` file that you can customize as the base for all emails.
49
+ This creates the `ApplicationEmail` class at `app/emails/application_email.rb` where you can customize the base for all emails, including setting defaults like the `from` address.
20
50
 
21
51
  ```ruby
22
- class ApplicationEmail < Supermail::Email
23
- def from = "Supermail <noreply@supermail.com>"
24
-
25
- class HTML
26
- def after_template
27
- p { "Best, The Supermail Team" }
28
- end
29
- end
30
-
31
- class Text
32
- def after_template
33
- "Best,\nThe Supermail Team"
34
- end
52
+ class ApplicationEmail < Supermail::Rails::Base
53
+ def from = "website@example.com"
54
+ def to = nil
55
+ def subject = nil
56
+ def body
57
+ <<~_
58
+ #{yield if block_given?}
59
+
60
+ Best,
61
+
62
+ The Example.com Team
63
+ _
35
64
  end
36
65
  end
37
66
  ```
@@ -44,32 +73,41 @@ To generate a new email, run the following command:
44
73
  rails generate supermail:email User::Welcome
45
74
  ```
46
75
 
47
- This will create a new email class in `app/mailers/user/welcome.rb`.
76
+ This will create a new email class in `app/mailers/user/welcome_email.rb`.
48
77
 
49
78
  ```ruby
50
79
  # ./app/email/user/welcome.rb
51
- class User::Welcome < ApplicationEmail
52
- def initialize(user:)
53
- @user = user
54
- end
55
-
56
- def subject = "Welcome to Supermail!"
80
+ class User::WelcomeEmail < ApplicationEmail
81
+ def body = <<~PLAIN
82
+ Hello there!
83
+ PLAIN
84
+ end
85
+ ```
86
+ You can customize the email by overriding the `to`, `from`, `subject`, and `body` methods.s
57
87
 
58
- class HTML
59
- def view_template
60
- h1 { "Welcome, #{@user.name}!" }
61
- p { "We're excited to have you on board." }
62
- end
88
+ ```ruby
89
+ # ./app/email/user/welcome.rb
90
+ class User::WelcomeEmail < ApplicationEmail
91
+ def initialize(person:)
92
+ @person = person
63
93
  end
64
94
 
65
- class Text
66
- def view_template
67
- "Welcome, #{@user.name}!\n\nWe're excited to have you on board."
95
+ def to = @person.email
96
+ def subject = "Welcome to the website"
97
+ def body
98
+ super do
99
+ <<~_
100
+ Hi #{@person.name},
101
+
102
+ Welcome to the website We're excited to have you on board.
103
+ _
68
104
  end
69
105
  end
70
106
  end
71
107
  ```
72
108
 
109
+ ### Send emails from the server
110
+
73
111
  Then, to send the email.
74
112
 
75
113
  ```ruby
@@ -82,6 +120,42 @@ If you want to tweak the message on the fly, you can modify the message, then de
82
120
  User::Welcome.new(user: User.first).message.tap do
83
121
  it.to << "another@example.com"
84
122
  end.deliver_now
123
+ ```
124
+
125
+ ### Launch the user's email client
126
+
127
+ Supermail clases can be used to generate `mailto:` links with Rails helpers.
128
+
129
+ ```erb
130
+ <%= link_to Support::OrderEmail.new(
131
+ user: current_user,
132
+ order: @order
133
+ ).mail_to s%>
134
+ ```
135
+
136
+ This opens your users email client with prefilled information. A support email about an order might look like this:
137
+
138
+ ```ruby
139
+ class Support::OrderEmail < ApplicationEmail
140
+ def initialize(user:, order:)
141
+ @user = user
142
+ @order = order
143
+ end
144
+
145
+ def to = "support@example.com"
146
+ def from = @user.email
147
+ def subject = "Question about order #{@order.id}"
148
+ def body = <<~BODY
149
+ Hi Support,
150
+
151
+ I need help with my order #{@order.id}.
152
+
153
+ Thanks,
154
+
155
+ #{@user.name}
156
+ BODY
157
+ end
158
+ ```
85
159
 
86
160
  ## Development
87
161
 
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rails/generators/named_base'
4
+
5
+ module Supermail
6
+ class EmailGenerator < ::Rails::Generators::NamedBase
7
+ source_root File.expand_path('templates', __dir__)
8
+
9
+ desc "Generate a new email class"
10
+
11
+ def create_email_file
12
+ template 'email.rb', "app/emails/#{file_path}_email.rb"
13
+ end
14
+
15
+ private
16
+
17
+ def file_path
18
+ name.underscore
19
+ end
20
+
21
+ def class_name
22
+ name.camelize
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ class <%= class_name %>Email < ApplicationEmail
4
+ def body = <<~PLAIN
5
+
6
+ PLAIN
7
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rails/generators/base'
4
+
5
+ module Supermail
6
+ class InstallGenerator < ::Rails::Generators::Base
7
+ source_root File.expand_path('templates', __dir__)
8
+
9
+ desc "Install Supermail in a Rails application"
10
+
11
+ def create_application_email
12
+ template 'application_email.rb', 'app/emails/application_email.rb'
13
+ end
14
+
15
+ def create_emails_directory
16
+ empty_directory 'app/emails'
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,13 @@
1
+ class ApplicationEmail < Supermail::Rails::Base
2
+ def from = "website@example.com"
3
+
4
+ def body
5
+ <<~_
6
+ #{yield if block_given?}
7
+
8
+ Best,
9
+
10
+ The Example.com Team
11
+ _
12
+ end
13
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Supermail
4
- VERSION = "0.1.0"
4
+ VERSION = "0.2.1"
5
5
  end
data/lib/supermail.rb CHANGED
@@ -1,85 +1,58 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require_relative "supermail/version"
4
-
5
- require 'mail'
6
- require "supermail/version"
4
+ require "action_mailer"
5
+ require "erb"
7
6
 
8
7
  module Supermail
9
8
  class Error < StandardError; end
10
9
 
11
- # A simple Email builder that wraps Mail::Message
12
- class Email
13
- # Hook to ensure default initialization runs before any subclass initialize
14
- module Defaults
15
- def initialize(*args, &block)
16
- # default fields
17
- @cc = []
18
- @bcc = []
19
- @headers = {}
20
- @attachments = []
21
- super
10
+ module Rails
11
+ class Base
12
+ delegate \
13
+ :deliver,
14
+ :deliver_now,
15
+ :deliver_later,
16
+ :message,
17
+ to: :action_mailer_base_mail
18
+
19
+ def to = nil
20
+ def from = nil
21
+ def subject = nil
22
+ def cc = []
23
+ def bcc = []
24
+ def body = ""
25
+
26
+ # Generate a mailto: URL with appropriate escaping.
27
+ def mailto = MailTo.href(to:, from:, cc:, bcc:, subject:, body:)
28
+ alias :mail_to :mailto
29
+
30
+ private def action_mailer_base_mail
31
+ ActionMailer::Base.mail(to:, from:, cc:, bcc:, subject:, body:)
22
32
  end
23
33
  end
34
+ end
24
35
 
25
- # Whenever subclassing, prepend Defaults to ensure it wraps initialize
26
- def self.inherited(subclass)
27
- subclass.prepend Defaults
28
- super
29
- end
30
-
31
- attr_accessor :from, :to, :cc, :bcc, :subject,
32
- :reply_to, :return_path, :date, :message_id,
33
- :in_reply_to, :references, :headers,
34
- :text_body, :html_body, :attachments
35
-
36
- # Builds a Mail::Message from this Email's attributes
37
- # @return [Mail::Message]
38
- def message
39
- mail = Mail.new
40
- mail.from = Array(from) if from
41
- mail.to = Array(to)
42
- mail.cc = cc if cc.any?
43
- mail.bcc = bcc if bcc.any?
44
- mail.reply_to = Array(reply_to) if reply_to
45
- mail.return_path = return_path if return_path
46
- mail.date = date if date
47
- mail.message_id = message_id if message_id
48
- mail.in_reply_to = in_reply_to if in_reply_to
49
- mail.references = references if references
50
-
51
- # Custom headers
52
- headers.each { |key, value| mail.header[key] = value }
53
-
54
- mail.subject = subject if subject
55
-
56
- # Bodies
57
- if text_body
58
- mail.text_part = Mail::Part.new do
59
- body text_body
60
- end
61
- end
62
-
63
- if html_body
64
- mail.html_part = Mail::Part.new do
65
- content_type 'text/html; charset=UTF-8'
66
- body html_body
67
- end
68
- end
36
+ module MailTo
37
+ extend self
69
38
 
70
- # Attachments (each as a hash: { filename:, content: })
71
- attachments.each do |att|
72
- mail.add_file filename: att[:filename], content: att[:content]
73
- end
39
+ def href(to:, **params)
40
+ q = query(**params)
41
+ q.empty? ? "mailto:#{to}" : "mailto:#{to}?#{q}"
42
+ end
74
43
 
75
- mail
44
+ def query(**params)
45
+ params
46
+ .compact # drop nils
47
+ .reject { |k, v| v.is_a?(Array) && v.empty? } # drop empty arrays
48
+ .map { |k, v| "#{k}=#{mailto_escape(v)}" }
49
+ .join("&")
76
50
  end
77
51
 
78
- # Delivers the built Mail::Message via its configured delivery_method
79
- # @return [Mail::Message]
80
- def deliver
81
- raise Error, "`to` address is required" unless to
82
- message.deliver!
52
+ private
53
+
54
+ def mailto_escape(str)
55
+ ERB::Util.url_encode(str.to_s).tr("+", "%20")
83
56
  end
84
57
  end
85
58
  end
metadata CHANGED
@@ -1,28 +1,42 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: supermail
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Brad Gessler
8
8
  bindir: exe
9
9
  cert_chain: []
10
- date: 2025-04-17 00:00:00.000000000 Z
10
+ date: 2025-09-29 00:00:00.000000000 Z
11
11
  dependencies:
12
12
  - !ruby/object:Gem::Dependency
13
- name: mail
13
+ name: actionmailer
14
14
  requirement: !ruby/object:Gem::Requirement
15
15
  requirements:
16
- - - "~>"
16
+ - - ">="
17
17
  - !ruby/object:Gem::Version
18
- version: '2.0'
18
+ version: '7.0'
19
19
  type: :runtime
20
20
  prerelease: false
21
21
  version_requirements: !ruby/object:Gem::Requirement
22
22
  requirements:
23
- - - "~>"
23
+ - - ">="
24
24
  - !ruby/object:Gem::Version
25
- version: '2.0'
25
+ version: '7.0'
26
+ - !ruby/object:Gem::Dependency
27
+ name: rails
28
+ requirement: !ruby/object:Gem::Requirement
29
+ requirements:
30
+ - - ">="
31
+ - !ruby/object:Gem::Version
32
+ version: '7.0'
33
+ type: :development
34
+ prerelease: false
35
+ version_requirements: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - ">="
38
+ - !ruby/object:Gem::Version
39
+ version: '7.0'
26
40
  description: Build emails with plain ol' Ruby objects.
27
41
  email:
28
42
  - bradgessler@gmail.com
@@ -33,16 +47,20 @@ files:
33
47
  - ".rspec"
34
48
  - README.md
35
49
  - Rakefile
50
+ - lib/generators/supermail/email/email_generator.rb
51
+ - lib/generators/supermail/email/templates/email.rb.tt
52
+ - lib/generators/supermail/install/install_generator.rb
53
+ - lib/generators/supermail/install/templates/application_email.rb.tt
36
54
  - lib/supermail.rb
37
55
  - lib/supermail/version.rb
38
56
  - sig/supermail.rbs
39
- homepage: https://github.com/rubymonolith/supermail
57
+ homepage: https://github.com/beautifulruby/supermail
40
58
  licenses: []
41
59
  metadata:
42
60
  allowed_push_host: https://rubygems.org
43
- homepage_uri: https://github.com/rubymonolith/supermail
44
- source_code_uri: https://github.com/rubymonolith/supermail
45
- changelog_uri: https://github.com/rubymonolith/supermail
61
+ homepage_uri: https://github.com/beautifulruby/supermail
62
+ source_code_uri: https://github.com/beautifulruby/supermail
63
+ changelog_uri: https://github.com/beautifulruby/supermail
46
64
  rdoc_options: []
47
65
  require_paths:
48
66
  - lib