letter_opener-1.10.0/ 0000755 0000041 0000041 00000000000 14620142103 014461 5 ustar www-data www-data letter_opener-1.10.0/lib/ 0000755 0000041 0000041 00000000000 14620142103 015227 5 ustar www-data www-data letter_opener-1.10.0/lib/letter_opener.rb 0000644 0000041 0000041 00000000565 14620142103 020431 0 ustar www-data www-data module LetterOpener
autoload :Message, "letter_opener/message"
autoload :DeliveryMethod, "letter_opener/delivery_method"
autoload :Configuration, "letter_opener/configuration"
def self.configuration
@configuration ||= Configuration.new
end
def self.configure
yield(configuration)
end
end
require "letter_opener/railtie" if defined?(Rails::Railtie)
letter_opener-1.10.0/lib/letter_opener/ 0000755 0000041 0000041 00000000000 14620142103 020076 5 ustar www-data www-data letter_opener-1.10.0/lib/letter_opener/configuration.rb 0000644 0000041 0000041 00000000511 14620142103 023267 0 ustar www-data www-data module LetterOpener
class Configuration
attr_accessor :location, :message_template, :file_uri_scheme
def initialize
@location = Rails.root.join('tmp', 'letter_opener') if defined?(Rails) && Rails.respond_to?(:root) && Rails.root
@message_template = 'default'
@file_uri_scheme = nil
end
end
end
letter_opener-1.10.0/lib/letter_opener/templates/ 0000755 0000041 0000041 00000000000 14620142103 022074 5 ustar www-data www-data letter_opener-1.10.0/lib/letter_opener/templates/default.html.erb 0000644 0000041 0000041 00000007521 14620142103 025162 0 ustar www-data www-data
<% if mail.subject %>
<%= h mail.subject %>
<% end %>
<% if type == "plain" %>
<%= auto_link(h(body)) %>
<% else %>
<% end %>
letter_opener-1.10.0/lib/letter_opener/templates/light.html.erb 0000644 0000041 0000041 00000000352 14620142103 024640 0 ustar www-data www-data
<% if mail.subject %>
<%= h mail.subject %>
<% end %>
<%= body %>
letter_opener-1.10.0/lib/letter_opener/tasks/ 0000755 0000041 0000041 00000000000 14620142103 021223 5 ustar www-data www-data letter_opener-1.10.0/lib/letter_opener/tasks/letter_opener.rake 0000644 0000041 0000041 00000000214 14620142103 024733 0 ustar www-data www-data namespace :tmp do
task :letter_opener do
rm_rf Dir["tmp/letter_opener/[^.]*"], verbose: false
end
task clear: :letter_opener
end
letter_opener-1.10.0/lib/letter_opener/delivery_method.rb 0000644 0000041 0000041 00000002450 14620142103 023607 0 ustar www-data www-data require "digest/sha1"
require "launchy"
module LetterOpener
class DeliveryMethod
class InvalidOption < StandardError; end
attr_accessor :settings
def initialize(options = {})
options[:message_template] ||= LetterOpener.configuration.message_template
options[:location] ||= LetterOpener.configuration.location
options[:file_uri_scheme] ||= LetterOpener.configuration.file_uri_scheme
raise InvalidOption, "A location option is required when using the Letter Opener delivery method" if options[:location].nil?
self.settings = options
end
def deliver!(mail)
validate_mail!(mail)
location = File.join(settings[:location], "#{Time.now.to_f.to_s.tr('.', '_')}_#{Digest::SHA1.hexdigest(mail.encoded)[0..6]}")
messages = Message.rendered_messages(mail, location: location, message_template: settings[:message_template])
::Launchy.open("#{settings[:file_uri_scheme]}#{messages.first.filepath}")
end
private
def validate_mail!(mail)
if !mail.smtp_envelope_from || mail.smtp_envelope_from.empty?
raise ArgumentError, "SMTP From address may not be blank"
end
if !mail.smtp_envelope_to || mail.smtp_envelope_to.empty?
raise ArgumentError, "SMTP To address may not be blank"
end
end
end
end
letter_opener-1.10.0/lib/letter_opener/message.rb 0000644 0000041 0000041 00000007031 14620142103 022050 0 ustar www-data www-data require "cgi"
require "erb"
require "fileutils"
require "uri"
module LetterOpener
class Message
attr_reader :mail
def self.rendered_messages(mail, options = {})
messages = []
messages << new(mail, options.merge(part: mail.html_part)) if mail.html_part
messages << new(mail, options.merge(part: mail.text_part)) if mail.text_part
messages << new(mail, options) if messages.empty?
messages.each(&:render)
messages.sort
end
ERROR_MSG = '%s or default configuration must be given'.freeze
def initialize(mail, options = {})
@mail = mail
@location = options[:location] || LetterOpener.configuration.location
@part = options[:part]
@template = options[:message_template] || LetterOpener.configuration.message_template
@attachments = []
raise ArgumentError, ERROR_MSG % 'options[:location]' unless @location
raise ArgumentError, ERROR_MSG % 'options[:message_template]' unless @template
end
def render
FileUtils.mkdir_p(@location)
if mail.attachments.any?
attachments_dir = File.join(@location, 'attachments')
FileUtils.mkdir_p(attachments_dir)
mail.attachments.each do |attachment|
filename = attachment_filename(attachment)
path = File.join(attachments_dir, filename)
unless File.exist?(path) # true if other parts have already been rendered
File.open(path, 'wb') { |f| f.write(attachment.body.raw_source) }
end
@attachments << [attachment.filename, "attachments/#{filename}"]
end
end
File.open(filepath, 'w') do |f|
f.write ERB.new(template).result(binding)
end
mail["location_#{type}"] = filepath
end
def template
File.read(File.expand_path("../templates/#{@template}.html.erb", __FILE__))
end
def filepath
File.join(@location, "#{type}.html")
end
def content_type
@part && @part.content_type || @mail.content_type
end
def body
@body ||= begin
body = (@part || @mail).decoded
mail.attachments.each do |attachment|
body.gsub!(attachment.url, "attachments/#{attachment_filename(attachment)}")
end
body
end
end
def from
@from ||= Array(@mail['from']).join(", ")
end
def sender
@sender ||= Array(@mail['sender']).join(", ")
end
def subject
@subject ||= @mail.subject
end
def to
@to ||= Array(@mail['to']).join(", ")
end
def cc
@cc ||= Array(@mail['cc']).join(", ")
end
def bcc
@bcc ||= Array(@mail['bcc']).join(", ")
end
def reply_to
@reply_to ||= Array(@mail['reply-to']).join(", ")
end
def type
content_type =~ /html/ ? "rich" : "plain"
end
def encoding
body.respond_to?(:encoding) ? body.encoding : "utf-8"
end
def auto_link(text)
text.gsub(URI::Parser.new.make_regexp(%W[https http])) do |link|
"#{ link }"
end
end
def h(content)
CGI.escapeHTML(content)
end
def attachment_filename(attachment)
# Copied from https://github.com/rails/rails/blob/6bfc637659248df5d6719a86d2981b52662d9b50/activestorage/app/models/active_storage/filename.rb#L57
attachment.filename.encode(
Encoding::UTF_8, invalid: :replace, undef: :replace, replace: "�").strip.tr("\u{202E}%$|:;/\t\r\n\\", "-"
)
end
def <=>(other)
order = %w[rich plain]
order.index(type) <=> order.index(other.type)
end
end
end
letter_opener-1.10.0/lib/letter_opener/railtie.rb 0000644 0000041 0000041 00000000600 14620142103 022050 0 ustar www-data www-data module LetterOpener
class Railtie < Rails::Railtie
initializer "letter_opener.add_delivery_method" do
ActiveSupport.on_load :action_mailer do
ActionMailer::Base.add_delivery_method(
:letter_opener,
LetterOpener::DeliveryMethod
)
end
end
rake_tasks do
load 'letter_opener/tasks/letter_opener.rake'
end
end
end
letter_opener-1.10.0/spec/ 0000755 0000041 0000041 00000000000 14620142103 015413 5 ustar www-data www-data letter_opener-1.10.0/spec/spec_helper.rb 0000644 0000041 0000041 00000000247 14620142103 020234 0 ustar www-data www-data require 'rubygems'
require 'bundler/setup'
Bundler.require(:default)
require "mail"
RSpec.configure do |config|
config.run_all_when_everything_filtered = true
end
letter_opener-1.10.0/spec/letter_opener/ 0000755 0000041 0000041 00000000000 14620142103 020262 5 ustar www-data www-data letter_opener-1.10.0/spec/letter_opener/delivery_method_spec.rb 0000644 0000041 0000041 00000026602 14620142103 025012 0 ustar www-data www-data require "spec_helper"
describe LetterOpener::DeliveryMethod do
let(:location) { File.expand_path('../../../tmp/letter_opener', __FILE__) }
let(:file_uri_scheme) { nil }
let(:plain_file) { Dir["#{location}/*/plain.html"].first }
let(:plain) { CGI.unescape_html(File.read(plain_file)) }
before do
allow(Launchy).to receive(:open)
FileUtils.rm_rf(location)
context = self
Mail.defaults do
delivery_method LetterOpener::DeliveryMethod, location: context.location, file_uri_scheme: context.file_uri_scheme
end
end
it 'raises an exception if no location passed' do
expect { LetterOpener::DeliveryMethod.new }.to raise_exception(LetterOpener::DeliveryMethod::InvalidOption)
expect { LetterOpener::DeliveryMethod.new(location: "foo") }.to_not raise_exception
end
context 'integration' do
before do
expect(Launchy).to receive(:open).and_call_original
ENV['LAUNCHY_DRY_RUN'] = 'true'
end
context 'normal location path' do
it 'opens email' do
expect($stdout).to receive(:puts)
expect {
Mail.deliver do
to 'Bar bar@example.com'
from 'Foo foo@example.com'
body 'World! http://example.com'
end
}.not_to raise_error
end
end
context 'with spaces in location path' do
let(:location) { File.expand_path('../../../tmp/letter_opener with space', __FILE__) }
it 'opens email' do
expect($stdout).to receive(:puts)
expect {
Mail.deliver do
to 'Bar bar@example.com'
from 'Foo foo@example.com'
body 'World! http://example.com'
end
}.not_to raise_error
end
end
end
context 'content' do
context 'plain' do
before do
expect(Launchy).to receive(:open)
Mail.deliver do
from 'Foo '
sender 'Baz '
reply_to 'No Reply '
to 'Bar '
cc 'Qux '
bcc 'Qux '
subject 'Hello'
body 'World! http://example.com'
end
end
it 'creates plain html document' do
expect(File.exist?(plain_file)).to be_truthy
end
it 'saves From field' do
expect(plain).to include("Foo ")
end
it 'saves Sender field' do
expect(plain).to include("Baz ")
end
it 'saves Reply-to field' do
expect(plain).to include("No Reply ")
end
it 'saves To field' do
expect(plain).to include("Bar ")
end
it 'saves Subject field' do
expect(plain).to include("Hello")
end
it 'saves Body with autolink' do
expect(plain).to include('World! http://example.com')
end
end
context 'multipart' do
let(:rich_file) { Dir["#{location}/*/rich.html"].first }
let(:rich) { CGI.unescape_html(File.read(rich_file)) }
before do
expect(Launchy).to receive(:open)
Mail.deliver do
from 'foo@example.com'
to 'bar@example.com'
subject 'Many parts with '
text_part do
body 'This is text'
end
html_part do
content_type 'text/html; charset=UTF-8'
body 'This is HTML
'
end
end
end
it 'creates plain html document' do
expect(File.exist?(plain_file)).to be_truthy
end
it 'creates rich html document' do
expect(File.exist?(rich_file)).to be_truthy
end
it 'shows link to rich html version' do
expect(plain).to include("View HTML version")
end
it 'saves text part' do
expect(plain).to include("This is text")
end
it 'saves html part' do
expect(rich).to include("This is HTML
")
end
it 'saves escaped Subject field' do
expect(plain).to include("Many parts with ")
end
it 'shows subject as title' do
expect(rich).to include("Many parts with ")
end
end
end
context 'document with spaces in name' do
let(:location) { File.expand_path('../../../tmp/letter_opener with space', __FILE__) }
before do
expect(Launchy).to receive(:open)
Mail.deliver do
from 'Foo '
to 'bar@example.com'
subject 'Hello'
body 'World!'
end
end
it 'creates plain html document' do
File.exist?(plain_file)
end
it 'saves From filed' do
expect(plain).to include("Foo ")
end
end
context 'using deliver! method' do
before do
expect(Launchy).to receive(:open)
Mail.new do
from 'foo@example.com'
to 'bar@example.com'
subject 'Hello'
body 'World!'
end.deliver!
end
it 'creates plain html document' do
expect(File.exist?(plain_file)).to be_truthy
end
it 'saves From field' do
expect(plain).to include("foo@example.com")
end
it 'saves To field' do
expect(plain).to include("bar@example.com")
end
it 'saves Subject field' do
expect(plain).to include("Hello")
end
it 'saves Body field' do
expect(plain).to include("World!")
end
end
context 'attachments in plain text mail' do
before do
Mail.deliver do
from 'foo@example.com'
to 'bar@example.com'
subject 'With attachments'
text_part do
body 'This is text'
end
attachments[File.basename(__FILE__)] = File.read(__FILE__)
end
end
it 'creates attachments dir with attachment' do
attachment = Dir["#{location}/*/attachments/#{File.basename(__FILE__)}"].first
expect(File.exist?(attachment)).to be_truthy
end
it 'saves attachment name' do
plain = File.read(Dir["#{location}/*/plain.html"].first)
expect(plain).to include(File.basename(__FILE__))
end
end
context 'attachments in rich mail' do
let(:url) { mail.attachments[0].url }
let!(:mail) do
Mail.deliver do
from 'foo@example.com'
to 'bar@example.com'
subject 'With attachments'
attachments[File.basename(__FILE__)] = File.read(__FILE__)
url = attachments[0].url
html_part do
content_type 'text/html; charset=UTF-8'
body "Here's an image:
"
end
end
end
it 'creates attachments dir with attachment' do
attachment = Dir["#{location}/*/attachments/#{File.basename(__FILE__)}"].first
expect(File.exist?(attachment)).to be_truthy
end
it 'replaces inline attachment urls' do
text = File.read(Dir["#{location}/*/rich.html"].first)
expect(mail.parts[0].body).to include(url)
expect(text).to_not include(url)
expect(text).to include("attachments/#{File.basename(__FILE__)}")
end
end
context 'attachments with non-word characters in the filename' do
before do
Mail.deliver do
from 'foo@example.com'
to 'bar@example.com'
subject 'With attachments'
text_part do
body 'This is text'
end
attachments['non word:chars/used,01-02.txt'] = File.read(__FILE__)
url = attachments[0].url
html_part do
content_type 'text/html; charset=UTF-8'
body "This is an image:
"
end
end
end
it 'creates attachments dir with attachment' do
attachment = Dir["#{location}/*/attachments/non word-chars-used,01-02.txt"].first
expect(File.exist?(attachment)).to be_truthy
end
it 'saves attachment name' do
plain = File.read(Dir["#{location}/*/plain.html"].first)
expect(plain).to include('non word-chars-used,01-02.txt')
end
it 'replaces inline attachment names' do
text = File.read(Dir["#{location}/*/rich.html"].first)
expect(text).to include('attachments/non word-chars-used,01-02.txt')
end
end
context 'subjectless mail' do
before do
expect(Launchy).to receive(:open)
Mail.deliver do
from 'Foo foo@example.com'
reply_to 'No Reply no-reply@example.com'
to 'Bar bar@example.com'
body 'World! http://example.com'
end
end
it 'creates plain html document' do
expect(File.exist?(plain_file)).to be_truthy
end
end
context 'delivery params' do
it 'raises an exception if there is no SMTP Envelope To value' do
expect(Launchy).not_to receive(:open)
expect {
Mail.deliver do
from 'Foo foo@example.com'
reply_to 'No Reply no-reply@example.com'
body 'World! http://example.com'
end
}.to raise_exception(ArgumentError)
end
it 'does not raise an exception if there is at least one SMTP Envelope To value' do
expect(Launchy).to receive(:open)
expect {
Mail.deliver do
from 'Foo foo@example.com'
cc 'Bar bar@example.com'
reply_to 'No Reply no-reply@example.com'
body 'World! http://example.com'
end
}.not_to raise_exception
end
end
context 'light template' do
before do
expect(Launchy).to receive(:open)
LetterOpener.configure do |config|
config.message_template = :light
end
Mail.defaults do
delivery_method LetterOpener::DeliveryMethod, :location => File.expand_path('../../../tmp/letter_opener', __FILE__)
end
Mail.deliver do
subject 'Foo subject'
from 'Foo foo@example.com'
reply_to 'No Reply no-reply@example.com'
to 'Bar bar@example.com'
body 'World! http://example.com'
end
end
after do
LetterOpener.configure do |config|
config.message_template = :default
end
end
it 'creates plain html document' do
expect(File.exist?(plain_file)).to be_truthy
end
end
context 'specifying custom file_uri_scheme configuration option' do
after do
Mail.defaults do
delivery_method LetterOpener::DeliveryMethod, location: File.expand_path('../../../tmp/letter_opener', __FILE__)
end
Mail.deliver do
subject 'Foo subject'
from 'Foo foo@example.com'
reply_to 'No Reply no-reply@example.com'
to 'Bar bar@example.com'
body 'World! http://example.com'
end
LetterOpener.configure do |config|
config.file_uri_scheme = file_uri_scheme
end
end
context 'file_uri_scheme is not set in configuration' do
it "sends the path to Launchy with the 'file://' prefix by default" do
allow(Launchy).to receive(:open) do |path|
expect(path).not_to match(/^file:\/\//)
end
end
end
context 'file_uri_scheme is set in configuration' do
it "sends the path to Launchy with the 'file://///wsl$/Ubuntu-18.04' prefix" do
allow(Launchy).to receive(:open) do |path|
expect(path).to match(/^file:\/\/\/\/\/wsl\$\/Ubuntu-18.04/)
end
LetterOpener.configure do |config|
config.file_uri_scheme = 'file://///wsl$/Ubuntu-18.04'
end
end
end
end
end
letter_opener-1.10.0/spec/letter_opener/message_spec.rb 0000644 0000041 0000041 00000022751 14620142103 023254 0 ustar www-data www-data # encoding: utf-8
require 'spec_helper'
describe LetterOpener::Message do
let(:location) { File.expand_path('../../../tmp/letter_opener', __FILE__) }
def mail(options={}, &blk)
Mail.new(options, &blk)
end
describe '#reply_to' do
it 'handles one email as a string' do
mail = mail(:reply_to => 'test@example.com')
message = described_class.new(mail, location: location)
expect(message.reply_to).to eq('test@example.com')
end
it 'handles one email with display names' do
mail = mail(:reply_to => 'test ')
message = described_class.new(mail, location: location)
expect(message.reply_to).to eq('test ')
end
it 'handles array of emails' do
mail = mail(:reply_to => ['test1@example.com', 'test2@example.com'])
message = described_class.new(mail, location: location)
expect(message.reply_to).to eq('test1@example.com, test2@example.com')
end
it 'handles array of emails with display names' do
mail = mail(:reply_to => ['test1 ', 'test2 '])
message = described_class.new(mail, location: location)
expect(message.reply_to).to eq('test1 , test2 ')
end
end
describe '#subject' do
it 'handles UTF-8 charset subject' do
mail = mail(:subject => 'test_mail')
message = described_class.new(mail, location: location)
expect(message.subject).to eq('test_mail')
end
it 'handles encode ISO-2022-JP charset subject' do
mail = mail(:subject => '=?iso-2022-jp?B?GyRCJUYlOSVIJWEhPCVrGyhC?=')
message = described_class.new(mail, location: location)
expect(message.subject).to eq('テストメール')
end
end
describe '#to' do
it 'handles one email as a string' do
mail = mail(:to => 'test@example.com')
message = described_class.new(mail, location: location)
expect(message.to).to eq('test@example.com')
end
it 'handles one email with display names' do
mail = mail(:to => 'test ')
message = described_class.new(mail, location: location)
expect(message.to).to eq('test ')
end
it 'handles array of emails' do
mail = mail(:to => ['test1@example.com', 'test2@example.com'])
message = described_class.new(mail, location: location)
expect(message.to).to eq('test1@example.com, test2@example.com')
end
it 'handles array of emails with display names' do
mail = mail(:to => ['test1 ', 'test2 '])
message = described_class.new(mail, location: location)
expect(message.to).to eq('test1 , test2 ')
end
end
describe '#cc' do
it 'handles one cc email as a string' do
mail = mail(:cc => 'test@example.com')
message = described_class.new(mail, location: location)
expect(message.cc).to eq('test@example.com')
end
it 'handles one cc email with display name' do
mail = mail(:cc => ['test ', 'test2 '])
message = described_class.new(mail, location: location)
expect(message.cc).to eq('test , test2 ')
end
it 'handles array of cc emails' do
mail = mail(:cc => ['test1@example.com', 'test2@example.com'])
message = described_class.new(mail, location: location)
expect(message.cc).to eq('test1@example.com, test2@example.com')
end
it 'handles array of cc emails with display names' do
mail = mail(:cc => ['test ', 'test2 '])
message = described_class.new(mail, location: location)
expect(message.cc).to eq('test , test2 ')
end
end
describe '#bcc' do
it 'handles one bcc email as a string' do
mail = mail(:bcc => 'test@example.com')
message = described_class.new(mail, location: location)
expect(message.bcc).to eq('test@example.com')
end
it 'handles one bcc email with display name' do
mail = mail(:bcc => ['test ', 'test2 '])
message = described_class.new(mail, location: location)
expect(message.bcc).to eq('test , test2 ')
end
it 'handles array of bcc emails' do
mail = mail(:bcc => ['test1@example.com', 'test2@example.com'])
message = described_class.new(mail, location: location)
expect(message.bcc).to eq('test1@example.com, test2@example.com')
end
it 'handles array of bcc emails with display names' do
mail = mail(:bcc => ['test ', 'test2 '])
message = described_class.new(mail, location: location)
expect(message.bcc).to eq('test , test2 ')
end
end
describe '#sender' do
it 'handles one email as a string' do
mail = mail(:sender => 'sender@example.com')
message = described_class.new(mail, location: location)
expect(message.sender).to eq('sender@example.com')
end
it 'handles one email as a string with display name' do
mail = mail(:sender => 'test ')
message = described_class.new(mail, location: location)
expect(message.sender).to eq('test ')
end
it 'handles array of emails' do
mail = mail(:sender => ['sender1@example.com', 'sender2@example.com'])
message = described_class.new(mail, location: location)
expect(message.sender).to eq('sender1@example.com, sender2@example.com')
end
it 'handles array of emails with display names' do
mail = mail(:sender => ['test ', 'test2 '])
message = described_class.new(mail, location: location)
expect(message.sender).to eq('test , test2 ')
end
end
describe '#<=>' do
it 'sorts rich type before plain type' do
plain = described_class.new(double(content_type: 'text/plain'), location: location)
rich = described_class.new(double(content_type: 'text/html'), location: location)
expect([plain, rich].sort).to eq([rich, plain])
end
end
describe '#auto_link' do
let(:message){ described_class.new(mail, location: location) }
it 'does not modify unlinkable text' do
text = 'the quick brown fox jumped over the lazy dog'
expect(message.auto_link(text)).to eq(text)
end
it 'adds links for http' do
raw = "Link to http://localhost:3000/example/path path"
linked = "Link to http://localhost:3000/example/path path"
expect(message.auto_link(raw)).to eq(linked)
end
end
describe '#body' do
it 'handles UTF-8 charset body correctly, with QP CTE, for a non-multipart message' do
mail = mail(:sender => 'sender@example.com') do
content_type "text/html; charset=UTF-8"
content_transfer_encoding 'quoted-printable'
body "☃"
end
message = message = described_class.new(mail, location: location)
expect(message.body.encoding.name).to eq('UTF-8')
end
it 'handles UTF-8 charset HTML part body correctly, with QP CTE, for a multipart message' do
mail = mail(:sender => 'sender@example.com') do
html_part do
content_type "text/html; charset=UTF-8"
content_transfer_encoding 'quoted-printable'
body "☃"
end
end
message = described_class.new(mail, location: location, part: mail.html_part)
expect(message.body.encoding.name).to eq('UTF-8')
end
it 'handles UTF-8 charset text part body correctly, with QP CTE, for a multipart message' do
mail = mail(:sender => 'sender@example.com') do
text_part do
content_type "text/plain; charset=UTF-8"
content_transfer_encoding 'quoted-printable'
body "☃"
end
end
message = described_class.new(mail, location: location, part: mail.text_part)
expect(message.body.encoding.name).to eq('UTF-8')
end
end
describe '#render' do
it 'records the saved email path for plain content type' do
mail = mail(:subject => 'test_mail')
message = described_class.new(mail, location: location)
message.render
expect(mail['location_plain'].value).to end_with('tmp/letter_opener/plain.html')
end
it 'records the saved email path for rich content type' do
mail = mail(:content_type => 'text/html', :subject => 'test_mail')
message = described_class.new(mail, location: location)
message.render
expect(mail['location_rich'].value).to end_with('tmp/letter_opener/rich.html')
end
end
describe '.rendered_messages' do
it 'uses configured default template if options not given' do
allow(LetterOpener.configuration).to receive(:location) { location }
messages = described_class.rendered_messages(mail)
expect(messages.first.template).not_to be_nil
end
it 'fails if necessary defaults are not provided' do
allow(LetterOpener.configuration).to receive(:location) { nil }
expect { described_class.rendered_messages(mail) }.to raise_error(ArgumentError)
end
it 'fails if necessary defaults are not provided' do
allow(LetterOpener.configuration).to receive(:message_template) { nil }
expect { described_class.rendered_messages(mail) }.to raise_error(ArgumentError)
end
end
end
letter_opener-1.10.0/letter_opener.gemspec 0000644 0000041 0000041 00000002230 14620142103 020672 0 ustar www-data www-data Gem::Specification.new do |s|
s.name = "letter_opener"
s.version = "1.10.0"
s.author = "Ryan Bates"
s.email = "ryan@railscasts.com"
s.homepage = "https://github.com/ryanb/letter_opener"
s.summary = "Preview mail in browser instead of sending."
s.description = "When mail is sent from your application, Letter Opener will open a preview in the browser instead of sending."
s.license = "MIT"
s.files = Dir["{lib,spec}/**/*", "[A-Z]*"] - ["Gemfile.lock"]
s.require_path = "lib"
s.add_dependency 'launchy', '>= 2.2', '< 4'
s.add_development_dependency 'rspec', '~> 3.10.0'
s.add_development_dependency 'mail', '~> 2.6.0'
s.required_rubygems_version = ">= 1.3.4"
if s.respond_to?(:metadata)
s.metadata = {
'bug_tracker_uri' => 'https://github.com/ryanb/letter_opener/issues',
'changelog_uri' => 'https://github.com/ryanb/letter_opener/blob/master/CHANGELOG.md',
'documentation_uri' => 'http://www.rubydoc.info/gems/letter_opener/',
'homepage_uri' => 'https://github.com/ryanb/letter_opener',
'source_code_uri' => 'https://github.com/ryanb/letter_opener/',
}
end
end
letter_opener-1.10.0/Rakefile 0000644 0000041 0000041 00000000264 14620142103 016130 0 ustar www-data www-data require 'bundler'
Bundler::GemHelper.install_tasks
require 'rspec/core/rake_task'
desc "Run RSpec"
RSpec::Core::RakeTask.new do |t|
t.verbose = false
end
task :default => :spec
letter_opener-1.10.0/Gemfile 0000644 0000041 0000041 00000000326 14620142103 015755 0 ustar www-data www-data source "https://rubygems.org"
gemspec
if Gem::Version.new(RUBY_VERSION) >= Gem::Version.new("3.1")
gem "net-imap", require: false
gem "net-pop", require: false
gem "net-smtp", require: false
end
gem "rake"
letter_opener-1.10.0/LICENSE 0000644 0000041 0000041 00000002036 14620142103 015467 0 ustar www-data www-data Copyright (c) 2012 Ryan Bates
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
letter_opener-1.10.0/README.md 0000644 0000041 0000041 00000010352 14620142103 015741 0 ustar www-data www-data # Letter Opener [](https://github.com/ryanb/letter_opener/actions/workflows/ruby.yml)
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.
## Rails Setup
First add the gem to your development environment and run the `bundle` command to install it.
```rb
gem "letter_opener", group: :development
```
Then set the delivery method in `config/environments/development.rb`
```rb
config.action_mailer.delivery_method = :letter_opener
config.action_mailer.perform_deliveries = true
```
Now any email will pop up in your browser instead of being sent. The messages are stored in `tmp/letter_opener`.
If you want to change application that will be used to open your emails you should override `LAUNCHY_APPLICATION` environment variable or set `Launchy.application` in the initializer.
### Configuration
```rb
LetterOpener.configure do |config|
# To overrider the location for message storage.
# Default value is `tmp/letter_opener`
config.location = Rails.root.join('tmp', 'my_mails')
# To render only the message body, without any metadata or extra containers or styling.
# Default value is `:default` that renders styled message with showing useful metadata.
config.message_template = :light
# To change default file URI scheme you can provide `file_uri_scheme` config.
# It might be useful when you use WSL (Windows Subsystem for Linux) and default
# scheme doesn't work for you.
# Default value is blank
config.file_uri_scheme = 'file://///wsl$/Ubuntu-18.04'
end
```
## Non Rails Setup
If you aren't using Rails, this can be easily set up with the Mail gem. Just set the delivery method when configuring Mail and specify a location.
```rb
require "letter_opener"
Mail.defaults do
delivery_method LetterOpener::DeliveryMethod, location: File.expand_path('../tmp/letter_opener', __FILE__)
end
```
The method is similar if you're using the Pony gem:
```rb
require "letter_opener"
Pony.options = {
via: LetterOpener::DeliveryMethod,
via_options: {location: File.expand_path('../tmp/letter_opener', __FILE__)}
}
```
Alternatively, if you are using ActionMailer directly (without Rails) you will need to add the delivery method.
```rb
require "letter_opener"
ActionMailer::Base.add_delivery_method :letter_opener, LetterOpener::DeliveryMethod, :location => File.expand_path('../tmp/letter_opener', __FILE__)
ActionMailer::Base.delivery_method = :letter_opener
```
## Remote Alternatives
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/).
If you are running your application within a Docker Container or VM and do not have a browser available to open emails received by Letter Opener, you may see the following error:
```
WARN: Launchy::CommandNotFoundError: Unable to find a browser command. If this is unexpected, Please rerun with environment variable LAUNCHY_DEBUG=true or the '-d' commandline option and file a bug at https://github.com/copiousfreetime/launchy/issues/new
```
To resolve this, simply set the following ENV variables:
```
LAUNCHY_DRY_RUN=true
BROWSER=/dev/null
```
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).
## Development & Feedback
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.
Special thanks to the [mail_view](https://github.com/37signals/mail_view/) gem for inspiring this project and for their mail template. Also thanks to [Vasiliy Ermolovich](https://github.com/nashby) for helping manage this project.
letter_opener-1.10.0/CHANGELOG.md 0000644 0000041 0000041 00000012135 14620142103 016274 0 ustar www-data www-data ## 1.10.0 ##
* Allow Launchy 3.0+.
## 1.9.0 ##
* Store mail location in `Mail::Message` object (thanks [Jonathan Chan](https://github.com/jonmchan))
* Drop Ruby 2 support. Support only Ruby 3.0+
* Remove `nkf` gem dependency.
## 1.8.1 ##
* Fix duplication of Rails tasks caused by LetterOpener's rake task file. (thanks [zarqman](https://github.com/zarqman))
## 1.8.0 ##
* Allow configuration of the 'file///' part in Launchy.open path (thanks [
Regis Millet](https://github.com/Kulgar))
* Enhance 'tmp:clear' task to delete 'tmp/letter_opener' files (thanks [Joaquín Vicente](https://github.com/wacko))
* Convert mail's subject to UTF-8. (thanks [kuroponzu](https://github.com/kuroponzu))
* Use proper attachment's filename sanitization so we don't escape Japanese characters.
## 1.7.0 ##
* Use default configuration in `Message::rendered_messages` (thanks [Krystan HuffMenne
](https://github.com/gitKrystan))
* Do not use `Rails.root` path if LetterOpener is used outside of Rails (thanks [centrevillage](https://github.com/centrevillage))
* Allow to set only `Mail#cc`/`Mail#bcc` without `Mail#to`.
## 1.6.0 ##
* Do not depend on Mail gem to check delivery params.
* Do not parse and escape url before passing it to Launchy.
## 1.5.0 ##
* Use proper check for `Rails::Railties` (thanks [Florian Weingarten](https://github.com/fw42))
* Add a shim for the iFrame "srcdoc" attribute (make it work with IE).
* Do not convert `-` to `_` in attachment file names. (thanks [Steven Harman](https://github.com/stevenharman))
* Drop Ruby 1.9 support.
* Escape inline attachment names the same way they are stored in the attachments directory (thanks [Daniel Rikowski](https://github.com/daniel-rikowski))
* Increase timestamp precision in the mail filename. (thanks [Piotr Usewicz](https://github.com/pusewicz))
* Add ability to configure location of stored mails. (thanks [Ben](https://github.com/beejamin))
* Add light version of template for mails that doesn't render any additional styling. (thanks [Ben](https://github.com/beejamin))
## 1.4.1 ##
* Stop base tag appearing in plain-text previews. (thanks [Coby Chapple](https://github.com/cobyism))
## 1.4.0 ##
* Add base tag to the iframe so links work with X-Frame-Options set to SAMEORIGIN. (thanks [Jason Tokoph](https://github.com/jtokoph))
* Check delivery params before rendering an email to match SMTP behaviour.
## 1.3.0 ##
* Fix message body encoding is observed correctly in QP CTE. (thanks [Mark Dodwell](https://github.com/mkdynamic))
* Remove fixed width on the mail content. (thanks [weexpectedTHIS](https://github.com/weexpectedTHIS))
* Render email content in the iframe. Fixes [#98](https://github.com/ryanb/letter_opener/issues/98). (thanks [Jacob Maine](https://github.com/mainej))
## 1.2.0 ##
* Fix auto_link() which in some cases would return an empty tag for plain text messages. (thanks [Kevin McPhillips](https://github.com/kmcphillips))
* Update styles. (thanks [Adam Doppelt](https://github.com/gurgeous))
## 1.1.2 ##
* Show formatted display names in html template (thanks [ClaireMcGinty](https://github.com/ClaireMcGinty))
* Use `file:///` uri scheme to fix Launchy on Windows.
## 1.1.1 ##
* Handle cc and bcc as array of emails. (thanks [jordandcarter](https://github.com/jordandcarter))
* Use `file://` uri scheme since Launcy can't open escaped URL without it. (thanks [Adrian2112](https://github.com/Adrian2112))
* Update Launchy dependency to `~> 2.2` (thanks [JeanMertz](https://github.com/JeanMertz))
* Change all nonword chars in filename of attachment to underscore so
it can be saved on all platforms. (thanks [phallstrom](https://github.com/phallstrom))
## 1.1.0 ##
* Update Launchy dependency to `~> 2.2.0` (thanks [webdevotion](https://github.com/webdevotion))
* Handle `sender` field (thanks [sjtipton](https://github.com/sjtipton))
* Show subject only if it's present (thanks [jadehyper](https://github.com/jadehyper))
* Show subject as title of web page (thanks [statique](https://github.com/statique))
## 1.0.0 ##
* Attachment Support (thanks [David Cornu](https://github.com/davidcornu))
* Escape HTML in subject and other fields
* Raise an exception if the :location option is not present instead of using a default
* Open rich version by default (thanks [Damir](https://github.com/sidonath))
* Override margin on dt and dd elements in CSS (thanks [Edgars Beigarts](https://github.com/ebeigarts))
* Autolink URLs in plain version (thanks [Matt Burke](https://github.com/spraints))
## 0.1.0 ##
* From and To show name and Email when specified
* Fix bug when letter_opener couldn't open email in Windows
* Handle spaces in the application path (thanks [Mike Boone](https://github.com/boone))
* 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))
* Handle `reply_to` field (thanks [Wes Gibbs](https://github.com/wgibbs))
* Set the charset in email preview (thanks [Bruno Michel](https://github.com/nono))
## 0.0.2 ##
* Fixing launchy requirement (thanks [Bruno Michel](https://github.com/nono))
## 0.0.1 ##
* Initial release