letter_opener 1.0.0 → 1.7.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 0ef387f446fe58d7fbe039333d493cc644dbb388323e098f2b4a0a48dfad93ac
4
+ data.tar.gz: 3d6da1bcc7fa1d575e00d361677e36a73dfd26ea331416cfbb31c14cdd8f87ac
5
+ SHA512:
6
+ metadata.gz: 62fc742943f4904086cfdddcd0908c7bb67fd602530e340852eb213644bce32e664e6da00058767fd80cfc8f13735e757e2d4fa32cb4459be74df8bdf7348030
7
+ data.tar.gz: 827cb033ed7805de3399f2c32427e69190a15420314d2f4ad6b4f3856a8209d6cbf0b0d5701ea6e47dd996fd919ef5e9185389df3b151ce24b3ad67a693492a6
data/CHANGELOG.md CHANGED
@@ -1,24 +1,82 @@
1
+ ## master ##
2
+ * Use default configuration in `Message::rendered_messages` (thanks [Krystan HuffMenne
3
+ ](https://github.com/gitKrystan))
4
+ * Do not use `Rails.root` path if LetterOpener is used outside of Rails (thanks [centrevillage](https://github.com/centrevillage))
5
+ * Allow to set only `Mail#cc`/`Mail#bcc` without `Mail#to`.
6
+
7
+ ## 1.6.0 ##
8
+ * Do not depend on Mail gem to check delivery params.
9
+ * Do not parse and escape url before passing it to Launchy.
10
+
11
+ ## 1.5.0 ##
12
+ * Use proper check for `Rails::Railties` (thanks [Florian Weingarten](https://github.com/fw42))
13
+ * Add a shim for the iFrame "srcdoc" attribute (make it work with IE).
14
+ * Do not convert `-` to `_` in attachment file names. (thanks [Steven Harman](https://github.com/stevenharman))
15
+ * Drop Ruby 1.9 support.
16
+ * Escape inline attachment names the same way they are stored in the attachments directory (thanks [Daniel Rikowski](https://github.com/daniel-rikowski))
17
+ * Increase timestamp precision in the mail filename. (thanks [Piotr Usewicz](https://github.com/pusewicz))
18
+ * Add ability to configure location of stored mails. (thanks [Ben](https://github.com/beejamin))
19
+ * Add light version of template for mails that doesn't render any additional styling. (thanks [Ben](https://github.com/beejamin))
20
+
21
+ ## 1.4.1 ##
22
+ * Stop base tag appearing in plain-text previews. (thanks [Coby Chapple](https://github.com/cobyism))
23
+
24
+ ## 1.4.0 ##
25
+ * Add base tag to the iframe so links work with X-Frame-Options set to SAMEORIGIN. (thanks [Jason Tokoph](https://github.com/jtokoph))
26
+ * Check delivery params before rendering an email to match SMTP behaviour.
27
+
28
+ ## 1.3.0 ##
29
+
30
+ * Fix message body encoding is observed correctly in QP CTE. (thanks [Mark Dodwell](https://github.com/mkdynamic))
31
+ * Remove fixed width on the mail content. (thanks [weexpectedTHIS](https://github.com/weexpectedTHIS))
32
+ * Render email content in the iframe. Fixes [#98](https://github.com/ryanb/letter_opener/issues/98). (thanks [Jacob Maine](https://github.com/mainej))
33
+
34
+ ## 1.2.0 ##
35
+
36
+ * Fix auto_link() which in some cases would return an empty <a> tag for plain text messages. (thanks [Kevin McPhillips](https://github.com/kmcphillips))
37
+ * Update styles. (thanks [Adam Doppelt](https://github.com/gurgeous))
38
+
39
+ ## 1.1.2 ##
40
+
41
+ * Show formatted display names in html template (thanks [ClaireMcGinty](https://github.com/ClaireMcGinty))
42
+ * Use `file:///` uri scheme to fix Launchy on Windows.
43
+
44
+ ## 1.1.1 ##
45
+
46
+ * Handle cc and bcc as array of emails. (thanks [jordandcarter](https://github.com/jordandcarter))
47
+ * Use `file://` uri scheme since Launcy can't open escaped URL without it. (thanks [Adrian2112](https://github.com/Adrian2112))
48
+ * Update Launchy dependency to `~> 2.2` (thanks [JeanMertz](https://github.com/JeanMertz))
49
+ * Change all nonword chars in filename of attachment to underscore so
50
+ it can be saved on all platforms. (thanks [phallstrom](https://github.com/phallstrom))
51
+
52
+ ## 1.1.0 ##
53
+
54
+ * Update Launchy dependency to `~> 2.2.0` (thanks [webdevotion](https://github.com/webdevotion))
55
+ * Handle `sender` field (thanks [sjtipton](https://github.com/sjtipton))
56
+ * Show subject only if it's present (thanks [jadehyper](https://github.com/jadehyper))
57
+ * Show subject as title of web page (thanks [statique](https://github.com/statique))
58
+
1
59
  ## 1.0.0 ##
2
60
 
3
- * Attachment Support (thanks David Cornu)
61
+ * Attachment Support (thanks [David Cornu](https://github.com/davidcornu))
4
62
  * Escape HTML in subject and other fields
5
63
  * Raise an exception if the :location option is not present instead of using a default
6
- * Open rich version by default (thanks Damir)
7
- * Override margin on dt and dd elements in CSS (thanks Edgars Beigarts)
8
- * Autolink URLs in plain version (thanks Matt Burke)
64
+ * Open rich version by default (thanks [Damir](https://github.com/sidonath))
65
+ * Override margin on dt and dd elements in CSS (thanks [Edgars Beigarts](https://github.com/ebeigarts))
66
+ * Autolink URLs in plain version (thanks [Matt Burke](https://github.com/spraints))
9
67
 
10
68
  ## 0.1.0 ##
11
69
 
12
70
  * From and To show name and Email when specified
13
71
  * Fix bug when letter_opener couldn't open email in Windows
14
- * Handle spaces in the application path (thanks Mike Boone)
15
- * As letter_opener doesn't work with Launchy < 2.0.4 let's depend on >= 2.0.4 (thanks Samnang Chhun)
16
- * Handle `reply_to` field (thanks Wes Gibbs)
17
- * Set the charset in email preview (thanks Bruno Michel)
72
+ * Handle spaces in the application path (thanks [Mike Boone](https://github.com/boone))
73
+ * As letter_opener doesn't work with Launchy < 2.0.4 let's depend on >= 2.0.4 (thanks [Samnang Chhun](https://github.com/samnang))
74
+ * Handle `reply_to` field (thanks [Wes Gibbs](https://github.com/wgibbs))
75
+ * Set the charset in email preview (thanks [Bruno Michel](https://github.com/nono))
18
76
 
19
77
  ## 0.0.2 ##
20
78
 
21
- * Fixing launchy requirement (thanks Bruno Michel)
79
+ * Fixing launchy requirement (thanks [Bruno Michel](https://github.com/nono))
22
80
 
23
81
  ## 0.0.1 ##
24
82
 
data/Gemfile CHANGED
@@ -1,4 +1,4 @@
1
- source "http://rubygems.org"
1
+ source "https://rubygems.org"
2
2
  gemspec
3
3
 
4
4
  gem "rake"
data/README.rdoc CHANGED
@@ -1,6 +1,6 @@
1
1
  = Letter Opener {<img src="https://secure.travis-ci.org/ryanb/letter_opener.png" />}[http://travis-ci.org/ryanb/letter_opener]
2
2
 
3
- Preview email in the browser instead of sending it. This means you do not need to set up email delivery in your development environment, and you no longer need to worry about accidentally sending a test email to someone else's address.
3
+ Preview email in the default browser instead of sending it. This means you do not need to set up email delivery in your development environment, and you no longer need to worry about accidentally sending a test email to someone else's address.
4
4
 
5
5
 
6
6
  == Rails Setup
@@ -12,9 +12,26 @@ First add the gem to your development environment and run the +bundle+ command t
12
12
  Then set the delivery method in <tt>config/environments/development.rb</tt>
13
13
 
14
14
  config.action_mailer.delivery_method = :letter_opener
15
+ config.action_mailer.perform_deliveries = true
15
16
 
16
17
  Now any email will pop up in your browser instead of being sent. The messages are stored in <tt>tmp/letter_opener</tt>.
18
+ If you want to change application that will be used to open your emails you should override <tt>LAUNCHY_APPLICATION</tt> environment variable or set <tt>Launchy.application</tt> in the initializer.
17
19
 
20
+ ==== Configuration
21
+
22
+ LetterOpener.configure do |config|
23
+ # To overrider the location for message storage.
24
+ # Default value is <tt>tmp/letter_opener</tt>
25
+ config.location = Rails.root.join('tmp', 'my_mails')
26
+
27
+ # To render only the message body, without any metadata or extra containers or styling.
28
+ # Default value is <tt>:default</tt> that renders styled message with showing useful metadata.
29
+ config.message_template = :light
30
+ end
31
+
32
+ ==== For Rails 2.3.x support
33
+
34
+ There is a fork that add support for Rails 2.3.x, in order to use that or just check it out you should go to https://github.com/cavi21/letter_opener
18
35
 
19
36
  == Non Rails Setup
20
37
 
@@ -25,6 +42,14 @@ If you aren't using Rails, this can be easily set up with the Mail gem. Just set
25
42
  delivery_method LetterOpener::DeliveryMethod, :location => File.expand_path('../tmp/letter_opener', __FILE__)
26
43
  end
27
44
 
45
+ The method is similar if you're using the Pony gem:
46
+
47
+ require "letter_opener"
48
+ Pony.options = {
49
+ :via => LetterOpener::DeliveryMethod,
50
+ :via_options => {:location => File.expand_path('../tmp/letter_opener', __FILE__)}
51
+ }
52
+
28
53
  Alternatively, if you are using ActionMailer directly (without Rails) you will need to add the delivery method.
29
54
 
30
55
  require "letter_opener"
@@ -32,6 +57,13 @@ Alternatively, if you are using ActionMailer directly (without Rails) you will n
32
57
  ActionMailer::Base.delivery_method = :letter_opener
33
58
 
34
59
 
60
+ == Remote Alternatives
61
+
62
+ Letter Opener uses {Launchy}[https://github.com/copiousfreetime/launchy] to open sent mail in the browser. This assumes the Ruby process is running on the local development machine. If you are using a separate staging server or VM this will not work. In that case consider using {Mailtrap}[http://mailtrap.io/] or {MailCatcher}[http://mailcatcher.me/].
63
+
64
+ In order to keep this project simple, I don't have plans to turn it into a Rails engine with an interface for browsing the sent mail but there is a {gem you can use for that}[https://github.com/fgrehm/letter_opener_web].
65
+
66
+
35
67
  == Development & Feedback
36
68
 
37
69
  Questions or problems? Please use the {issue tracker}[https://github.com/ryanb/letter_opener/issues]. If you would like to contribute to this project, fork this repository and run +bundle+ and +rake+ to run the tests. Pull requests appreciated.
@@ -0,0 +1,10 @@
1
+ module LetterOpener
2
+ class Configuration
3
+ attr_accessor :location, :message_template
4
+
5
+ def initialize
6
+ @location = Rails.root.join('tmp', 'letter_opener') if defined?(Rails) && Rails.respond_to?(:root)
7
+ @message_template = 'default'
8
+ end
9
+ end
10
+ end
@@ -1,3 +1,6 @@
1
+ require "digest/sha1"
2
+ require "launchy"
3
+
1
4
  module LetterOpener
2
5
  class DeliveryMethod
3
6
  class InvalidOption < StandardError; end
@@ -5,14 +8,32 @@ module LetterOpener
5
8
  attr_accessor :settings
6
9
 
7
10
  def initialize(options = {})
11
+ options[:message_template] ||= LetterOpener.configuration.message_template
12
+ options[:location] ||= LetterOpener.configuration.location
13
+
8
14
  raise InvalidOption, "A location option is required when using the Letter Opener delivery method" if options[:location].nil?
15
+
9
16
  self.settings = options
10
17
  end
11
18
 
12
19
  def deliver!(mail)
13
- location = File.join(settings[:location], "#{Time.now.to_i}_#{Digest::SHA1.hexdigest(mail.encoded)[0..6]}")
14
- messages = Message.rendered_messages(location, mail)
15
- Launchy.open(URI.parse(URI.escape(messages.first.filepath)))
20
+ validate_mail!(mail)
21
+ location = File.join(settings[:location], "#{Time.now.to_f.to_s.tr('.', '_')}_#{Digest::SHA1.hexdigest(mail.encoded)[0..6]}")
22
+
23
+ messages = Message.rendered_messages(mail, location: location, message_template: settings[:message_template])
24
+ Launchy.open("file:///#{messages.first.filepath}")
25
+ end
26
+
27
+ private
28
+
29
+ def validate_mail!(mail)
30
+ if !mail.smtp_envelope_from || mail.smtp_envelope_from.empty?
31
+ raise ArgumentError, "SMTP From address may not be blank"
32
+ end
33
+
34
+ if !mail.smtp_envelope_to || mail.smtp_envelope_to.empty?
35
+ raise ArgumentError, "SMTP To address may not be blank"
36
+ end
16
37
  end
17
38
  end
18
39
  end
@@ -1,21 +1,32 @@
1
+ require "cgi"
2
+ require "erb"
3
+ require "fileutils"
4
+ require "uri"
5
+
1
6
  module LetterOpener
2
7
  class Message
3
8
  attr_reader :mail
4
9
 
5
- def self.rendered_messages(location, mail)
10
+ def self.rendered_messages(mail, options = {})
6
11
  messages = []
7
- messages << new(location, mail, mail.html_part) if mail.html_part
8
- messages << new(location, mail, mail.text_part) if mail.text_part
9
- messages << new(location, mail) if messages.empty?
12
+ messages << new(mail, options.merge(part: mail.html_part)) if mail.html_part
13
+ messages << new(mail, options.merge(part: mail.text_part)) if mail.text_part
14
+ messages << new(mail, options) if messages.empty?
10
15
  messages.each(&:render)
11
16
  messages.sort
12
17
  end
13
18
 
14
- def initialize(location, mail, part = nil)
15
- @location = location
19
+ ERROR_MSG = '%s or default configuration must be given'.freeze
20
+
21
+ def initialize(mail, options = {})
16
22
  @mail = mail
17
- @part = part
23
+ @location = options[:location] || LetterOpener.configuration.location
24
+ @part = options[:part]
25
+ @template = options[:message_template] || LetterOpener.configuration.message_template
18
26
  @attachments = []
27
+
28
+ raise ArgumentError, ERROR_MSG % 'options[:location]' unless @location
29
+ raise ArgumentError, ERROR_MSG % 'options[:message_template]' unless @template
19
30
  end
20
31
 
21
32
  def render
@@ -25,13 +36,14 @@ module LetterOpener
25
36
  attachments_dir = File.join(@location, 'attachments')
26
37
  FileUtils.mkdir_p(attachments_dir)
27
38
  mail.attachments.each do |attachment|
28
- path = File.join(attachments_dir, attachment.filename)
39
+ filename = attachment_filename(attachment)
40
+ path = File.join(attachments_dir, filename)
29
41
 
30
- unless File.exists?(path) # true if other parts have already been rendered
42
+ unless File.exist?(path) # true if other parts have already been rendered
31
43
  File.open(path, 'wb') { |f| f.write(attachment.body.raw_source) }
32
44
  end
33
45
 
34
- @attachments << [attachment.filename, "attachments/#{URI.escape(attachment.filename)}"]
46
+ @attachments << [attachment.filename, "attachments/#{CGI.escape(filename)}"]
35
47
  end
36
48
  end
37
49
 
@@ -41,7 +53,7 @@ module LetterOpener
41
53
  end
42
54
 
43
55
  def template
44
- File.read(File.expand_path("../message.html.erb", __FILE__))
56
+ File.read(File.expand_path("../templates/#{@template}.html.erb", __FILE__))
45
57
  end
46
58
 
47
59
  def filepath
@@ -54,10 +66,10 @@ module LetterOpener
54
66
 
55
67
  def body
56
68
  @body ||= begin
57
- body = (@part && @part.body || @mail.body).to_s
69
+ body = (@part || @mail).decoded
58
70
 
59
71
  mail.attachments.each do |attachment|
60
- body.gsub!(attachment.url, "attachments/#{attachment.filename}")
72
+ body.gsub!(attachment.url, "attachments/#{attachment_filename(attachment)}")
61
73
  end
62
74
 
63
75
  body
@@ -65,15 +77,27 @@ module LetterOpener
65
77
  end
66
78
 
67
79
  def from
68
- @from ||= Array(@mail.from).join(", ")
80
+ @from ||= Array(@mail['from']).join(", ")
81
+ end
82
+
83
+ def sender
84
+ @sender ||= Array(@mail['sender']).join(", ")
69
85
  end
70
86
 
71
87
  def to
72
- @to ||= Array(@mail.to).join(", ")
88
+ @to ||= Array(@mail['to']).join(", ")
89
+ end
90
+
91
+ def cc
92
+ @cc ||= Array(@mail['cc']).join(", ")
93
+ end
94
+
95
+ def bcc
96
+ @bcc ||= Array(@mail['bcc']).join(", ")
73
97
  end
74
98
 
75
99
  def reply_to
76
- @reply_to ||= Array(@mail.reply_to).join(", ")
100
+ @reply_to ||= Array(@mail['reply-to']).join(", ")
77
101
  end
78
102
 
79
103
  def type
@@ -85,8 +109,8 @@ module LetterOpener
85
109
  end
86
110
 
87
111
  def auto_link(text)
88
- text.gsub(URI.regexp(%W[https http])) do
89
- "<a href=\"#{$&}\">#{$&}</a>"
112
+ text.gsub(URI::Parser.new.make_regexp(%W[https http])) do |link|
113
+ "<a href=\"#{ link }\">#{ link }</a>"
90
114
  end
91
115
  end
92
116
 
@@ -94,6 +118,10 @@ module LetterOpener
94
118
  CGI.escapeHTML(content)
95
119
  end
96
120
 
121
+ def attachment_filename(attachment)
122
+ attachment.filename.gsub(/[^\w\-.]/, '_')
123
+ end
124
+
97
125
  def <=>(other)
98
126
  order = %w[rich plain]
99
127
  order.index(type) <=> order.index(other.type)
@@ -1,7 +1,12 @@
1
1
  module LetterOpener
2
2
  class Railtie < Rails::Railtie
3
3
  initializer "letter_opener.add_delivery_method" do
4
- ActionMailer::Base.add_delivery_method :letter_opener, LetterOpener::DeliveryMethod, :location => Rails.root.join("tmp", "letter_opener")
4
+ ActiveSupport.on_load :action_mailer do
5
+ ActionMailer::Base.add_delivery_method(
6
+ :letter_opener,
7
+ LetterOpener::DeliveryMethod
8
+ )
9
+ end
5
10
  end
6
11
  end
7
12
  end
@@ -0,0 +1,138 @@
1
+ <html>
2
+ <head>
3
+ <meta http-equiv="Content-Type" content="text/html; charset=<%= encoding %>">
4
+ <% if mail.subject %>
5
+ <title><%= h mail.subject %></title>
6
+ <% end %>
7
+
8
+ <style type="text/css">
9
+ #container {
10
+ margin: 10px auto;
11
+ }
12
+ #message_headers {
13
+ background: #fff;
14
+ font-size: 12px;
15
+ font-family: "Segoe UI", "Helvetica Neue", Arial, sans-serif;
16
+ border-bottom: 1px solid #dedede;
17
+ margin-bottom: 10px;
18
+ overflow: auto;
19
+ }
20
+
21
+ #message_headers dl {
22
+ float: left;
23
+ line-height: 1.3em;
24
+ padding: 0;
25
+ }
26
+
27
+ #message_headers dt {
28
+ width: 92px;
29
+ margin: 0;
30
+ float: left;
31
+ text-align: right;
32
+ font-weight: bold;
33
+ color: #7f7f7f;
34
+ }
35
+
36
+ #message_headers dd {
37
+ margin: 0 0 0 102px;
38
+ }
39
+
40
+ #message_headers p.alternate {
41
+ float: right;
42
+ margin: 0;
43
+ }
44
+
45
+ #message_headers p.alternate a {
46
+ color: #09c;
47
+ }
48
+
49
+ pre#message_body {
50
+ padding: 4px;
51
+ white-space: pre-wrap;
52
+ border: 1px solid #eee;
53
+ background-color: #fcfcfc;
54
+ }
55
+
56
+ iframe {
57
+ border: 0;
58
+ width: 100%;
59
+ height: 100%;
60
+ }
61
+ </style>
62
+ </head>
63
+ <body>
64
+ <div id="container">
65
+ <div id="message_headers">
66
+ <dl>
67
+ <dt>From:</dt>
68
+ <dd><%= h from %></dd>
69
+
70
+ <% unless sender.empty? %>
71
+ <dt>Sender:</dt>
72
+ <dd><%= h sender %></dd>
73
+ <% end %>
74
+
75
+ <% unless reply_to.empty? %>
76
+ <dt>Reply-To:</dt>
77
+ <dd><%= h reply_to %></dd>
78
+ <% end %>
79
+
80
+ <% if mail.subject %>
81
+ <dt>Subject:</dt>
82
+ <dd><strong><%= h mail.subject %></strong></dd>
83
+ <% end %>
84
+
85
+ <dt>Date:</dt>
86
+ <dd><%= Time.now.strftime("%b %e, %Y %I:%M:%S %p %Z") %></dd>
87
+
88
+ <% unless to.empty? %>
89
+ <dt>To:</dt>
90
+ <dd><%= h to %></dd>
91
+ <% end %>
92
+
93
+ <% unless cc.empty? %>
94
+ <dt>CC:</dt>
95
+ <dd><%= h cc %></dd>
96
+ <% end %>
97
+
98
+ <% unless bcc.empty? %>
99
+ <dt>BCC:</dt>
100
+ <dd><%= h bcc %></dd>
101
+ <% end %>
102
+
103
+ <% if @attachments.any? %>
104
+ <dt>Attachments:</dt>
105
+ <dd>
106
+ <% @attachments.each do |filename, path| %>
107
+ <a href="<%= path %>"><%= filename %></a>&nbsp;
108
+ <% end %>
109
+ </dd>
110
+ <% end %>
111
+ </dl>
112
+
113
+ <% if mail.multipart? %>
114
+ <p class="alternate">
115
+ <% if type == "plain" && mail.html_part %>
116
+ <a href="rich.html">View HTML version</a>
117
+ <% elsif type == "rich" && mail.text_part %>
118
+ <a href="plain.html">View plain text version</a>
119
+ <% end %>
120
+ </p>
121
+ <% end %>
122
+ </div>
123
+
124
+ <% if type == "plain" %>
125
+ <pre id="message_body"><%= auto_link(h(body)) %></pre>
126
+ <% else %>
127
+ <iframe seamless="seamless" srcdoc="<base target='_top'><%= h(body) %>"></iframe>
128
+ <% end %>
129
+ </div>
130
+
131
+ <script type="text/javascript">
132
+ /*! srcdoc-polyfill - v0.1.1 - 2013-03-01
133
+ * http://github.com/jugglinmike/srcdoc-polyfill/
134
+ * Copyright (c) 2013 Mike Pennisi; Licensed MIT */
135
+ (function(t,e){var c,n,o=t.srcDoc,r=!!("srcdoc"in e.createElement("iframe")),i={compliant:function(t,e){e&&t.setAttribute("srcdoc",e)},legacy:function(t,e){var c;t&&t.getAttribute&&(e?t.setAttribute("srcdoc",e):e=t.getAttribute("srcdoc"),e&&(c="javascript: window.frameElement.getAttribute('srcdoc');",t.setAttribute("src",c),t.contentWindow&&(t.contentWindow.location=c)))}},s=t.srcDoc={set:i.compliant,noConflict:function(){return t.srcDoc=o,s}};if(!r)for(s.set=i.legacy,n=e.getElementsByTagName("iframe"),c=n.length;c--;)s.set(n[c])})(this,this.document);
136
+ </script>
137
+ </body>
138
+ </html>
@@ -0,0 +1,11 @@
1
+ <html>
2
+ <head>
3
+ <meta http-equiv="Content-Type" content="text/html; charset=<%= encoding %>">
4
+ <% if mail.subject %>
5
+ <title><%= h mail.subject %></title>
6
+ <% end %>
7
+ </head>
8
+ <body>
9
+ <%= body %>
10
+ </body>
11
+ </html>
data/lib/letter_opener.rb CHANGED
@@ -1,9 +1,15 @@
1
- require "fileutils"
2
- require "digest/sha1"
3
- require "cgi"
4
- require "uri"
5
- require "launchy"
1
+ module LetterOpener
2
+ autoload :Message, "letter_opener/message"
3
+ autoload :DeliveryMethod, "letter_opener/delivery_method"
4
+ autoload :Configuration, "letter_opener/configuration"
6
5
 
7
- require "letter_opener/message"
8
- require "letter_opener/delivery_method"
9
- require "letter_opener/railtie" if defined? Rails
6
+ def self.configuration
7
+ @configuration ||= Configuration.new
8
+ end
9
+
10
+ def self.configure
11
+ yield(configuration)
12
+ end
13
+ end
14
+
15
+ require "letter_opener/railtie" if defined?(Rails::Railtie)