pax_global_header00006660000000000000000000000064143331122620014507gustar00rootroot0000000000000052 comment=33287e89f7a330e1a2c55d15a59ab8ebab72d92f premailer-rails-1.12.0/000077500000000000000000000000001433311226200146605ustar00rootroot00000000000000premailer-rails-1.12.0/.github/000077500000000000000000000000001433311226200162205ustar00rootroot00000000000000premailer-rails-1.12.0/.github/workflows/000077500000000000000000000000001433311226200202555ustar00rootroot00000000000000premailer-rails-1.12.0/.github/workflows/test.yml000066400000000000000000000026751433311226200217710ustar00rootroot00000000000000name: Test on: push: branches: - "*" pull_request: branches: - "*" # Enable triggering CI runs manually. workflow_dispatch: concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true jobs: test: runs-on: ubuntu-latest continue-on-error: ${{ matrix.experimental }} strategy: fail-fast: false matrix: ruby: - '2.7' - '3.1' action_mailer_version: - 5 - 6 - 7 propshaft: - false - true experimental: - false exclude: - ruby: '3.1' action_mailer_version: 5 - action_mailer_version: 5 propshaft: true - action_mailer_version: 6 propshaft: true include: - ruby: head action_mailer_version: head propshaft: false experimental: true - ruby: head action_mailer_version: head propshaft: true experimental: true steps: - uses: actions/checkout@v3 - name: Set env vars run: | echo "ACTION_MAILER_VERSION=${{ matrix.action_mailer_version }}" >> $GITHUB_ENV echo "PROPSHAFT=${{ matrix.propshaft }}" >> $GITHUB_ENV - uses: ruby/setup-ruby@v1 with: ruby-version: ${{ matrix.ruby }} bundler-cache: true - run: bundle exec rake premailer-rails-1.12.0/.gitignore000066400000000000000000000001431433311226200166460ustar00rootroot00000000000000*.gem doc/ Gemfile.lock coverage/ spec/rails_app/log/* spec/rails_app/tmp/* .ruby-version /.bundle premailer-rails-1.12.0/.rspec000066400000000000000000000000251433311226200157720ustar00rootroot00000000000000--format doc --color premailer-rails-1.12.0/CHANGELOG.md000066400000000000000000000071211433311226200164720ustar00rootroot00000000000000# Changelog ## v1.12.0 - Lazily load actionmailer (@c960657, #260) - HTTP request for CSS files now have an `Accept: text/css` header (@ElMassimo, #261) - Added support for [Propshaft](https://github.com/rails/propshaft) (@Intrepidd, #277) ## v1.11.1 - Check if `Rails.application` is defined (@pabloh, #250) ## v1.11.0 - Remove `force_encoding!` ## v1.10.3 - Remove upper version constraint for actionmailer ## v1.10.2 - Explicitly check for assets_manifest (@derekwheel, #214) ## v1.10.1 - Catch error when sprockets can't find asset (@kirs, #209) ## v1.10.0 - Drop support for hpricot now that premailer-rails also doesn't support it - Use `Rails.application.assets_manifest` instead of `Rails.application.assets` in Asset Pipeline loader (@kirs, #201) - Introduce `:strategies` config option that allows to control CSS fetching stragies ## v1.9.7 - Use `Rails.root` in `FileSystemLoader` (@stanhu, #195) ## v1.9.6 - Handle `relative_url_root` in when loading CSS from file system ## v1.9.5 - Mention license in gemspec ## v1.9.4 - Improve check for Rails module - Preserve body encoding to prevent garbled mails ## v1.9.3 - Add support for rails' `relative_url_root` config - Fix link tag removal under Hpricot - Pass url to `asset_host` if it responds to `call` - Fixed issue where urls may conflict with folder names. ## v1.9.2 - Update rails dependency to allow rails 5 ## v1.9.1 - Respect data-premailer="ignore" on link tags - Ensure content-transfer-encoding is maintained ## v1.9.0 - Improved CSS loading and caching. - Fixed incompatibility with newer rails and sprockets versions. ## v1.8.2 - `Premailer::Rails::CSSLoaders::NetworkLoader` is more resilient and works even if the Rails asset host is set without a URI scheme. (panthomakos) - Remove stylesheet links from the HTML that have been processed. ## v1.8.1 - Add support for longer fingerprint generated by sprocket 3. ## v1.8.0 - `ActionMailer` interceptors are registered after Rails initialization and no longer when loading this gem. If you were using this gem outside Rails, you'll need to call `Premailer::Rails.register_interceptors` manually. ## v1.7.0 - Register preview hook for the new previewing functionality introduced in rails 4.1.0 - Add example rails application ## v1.6.1 - Remove Nokogiri unicode fix since it's working properly without it by now - Make sure html part comes before text part ## v1.6.0 - Only use asset pipeline if Rails is defined and if compile is true - Depend on actionmailer instead of rails - Check whether `::Rails` is defined before using it - Add ability to skip premailer - Test against multiple action mailer versions on travis - Ensure CSS strings are always UTF-8 encoded - Require premailer version >= 1.7.9 ## v1.5.1 - Prefer precompiled assets over asset pipeline - Improve construction of file URL when requesting from CDN - No longer use open-uri - Remove gzip unzipping after requesting file ## v1.5.0 - No longer support ruby 1.8 - Find linked stylesheets by `rel='stylesheet'` attribute instead of `type='text/css'` - Don't test hpricot on JRuby due to incompatibility ## v1.4.0 - Fix attachments ## v1.3.2 - Rename gem to premailer-rails (drop the 3) - Add support for rails 4 - Refactor code - Add support for precompiled assets - No longer include default `email.css` ## v1.1.0 - Fixed several bugs - Strip asset digest from CSS path - Improve nokogiri support - Request CSS file if asset is not found locally This allows you to host all your assets on a CDN and deploy the app without the `app/assets` folder. Thanks to everyone who contributed! premailer-rails-1.12.0/Gemfile000066400000000000000000000010471433311226200161550ustar00rootroot00000000000000source 'https://rubygems.org' git_source(:github) { |repo| "https://github.com/#{repo}.git" } gemspec rails_version = ENV.fetch('ACTION_MAILER_VERSION', '7') if rails_version == 'head' gem 'rails', github: 'rails/rails' if ENV['PROPSHAFT'] == 'true' gem 'propshaft', github: 'rails/propshaft' else gem 'sprockets-rails', github: 'rails/sprockets-rails' end else gem 'rails', "~> #{rails_version}" if ENV['PROPSHAFT'] == 'true' gem 'propshaft' else gem 'sprockets-rails' if rails_version >= '7' end end gem 'byebug' premailer-rails-1.12.0/LICENSE000066400000000000000000000020601433311226200156630ustar00rootroot00000000000000Copyright (C) 2011-2012 Philipe Fatio (fphilipe) 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.premailer-rails-1.12.0/README.md000066400000000000000000000166171433311226200161520ustar00rootroot00000000000000# premailer-rails CSS styled emails without the hassle. [![Build Status][build-image]][build-link] [![Gem Version][gem-image]][gem-link] [![Code Climate][gpa-image]][gpa-link] ## Introduction This gem is a drop in solution for styling HTML emails with CSS without having to do the hard work yourself. Styling emails is not just a matter of linking to a stylesheet. Most clients, especially web clients, ignore linked stylesheets or `

Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.

HTML TEXT_PART = <<-TEXT Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. TEXT def with_parts(*part_types) if part_types.count == 1 and [:html, :text].include?(part_types.first) return with_body(part_types.first) end message = base_message content_part = message if part_types.include?(:html) and part_types.include?(:text) content_part = Mail::Part.new(content_type: 'multipart/alternative') message.add_part(content_part) end if part_types.include? :html html_part = Mail::Part.new do body HTML_PART_WITH_CSS content_type 'text/html; charset=UTF-8' end content_part.html_part = html_part end if part_types.include? :text text_part = Mail::Part.new do body TEXT_PART content_type 'text/plain; charset=UTF-8' end content_part.text_part = text_part end if part_types.include? :attachment message.add_file(filename: 'foo.png', content: 'foobar') end message.ready_to_send! message end def with_body(body_type) message = base_message case body_type when :html message.body = HTML_PART_WITH_CSS message.content_type 'text/html; charset=UTF-8' when :text message.body = TEXT_PART message.content_type 'text/plain; charset=UTF-8' end message.ready_to_send! message end def latin_message base_message.tap do |message| message.body = HTML_PART message.content_type 'text/html; charset=UTF-8' message.ready_to_send! end end def non_latin_message base_message.tap do |message| message.body = HTML_PART_WITH_UNICODE message.content_type 'text/html; charset=UTF-8' message.ready_to_send! end end def greek_message base_message.tap do |message| message.body = HTML_PART_IN_GREEK message.content_type 'text/html; charset=ISO-8859-7' message.ready_to_send! end end def dash_message base_message.tap do |message| message.body = HTML_PART_WITH_DASHES message.content_type 'text/html; charset=UTF-8' message.ready_to_send! end end private def base_message Mail.new do to 'some@email.com' subject 'testing premailer-rails' end end end end premailer-rails-1.12.0/spec/unit/000077500000000000000000000000001433311226200165715ustar00rootroot00000000000000premailer-rails-1.12.0/spec/unit/css_loaders/000077500000000000000000000000001433311226200210725ustar00rootroot00000000000000premailer-rails-1.12.0/spec/unit/css_loaders/asset_pipeline_loader_spec.rb000066400000000000000000000036551433311226200267740ustar00rootroot00000000000000require 'spec_helper' if defined?(::Sprockets) describe Premailer::Rails::CSSLoaders::AssetPipelineLoader do before do allow(Rails.configuration) .to receive(:assets).and_return(double(prefix: '/assets')) allow(Rails.configuration).to receive(:relative_url_root).and_return(nil) end describe ".file_name" do subject do Premailer::Rails::CSSLoaders::AssetPipelineLoader.file_name(asset) end context "when asset file path contains prefix" do let(:asset) { '/assets/application.css' } it { is_expected.to eq('application.css') } end context "when asset file path contains prefix and relative_url_root is set" do before do allow(Rails.configuration) .to receive(:relative_url_root).and_return('/foo') end let(:asset) { '/foo/assets/application.css' } it { is_expected.to eq('application.css') } end context "when asset file path contains prefix and relative_url_root is set to root" do before do allow(Rails.configuration) .to receive(:relative_url_root).and_return('/') end let(:asset) { '/assets/application.css' } it { is_expected.to eq('application.css') } end context "when asset file path contains 32 chars fingerprint" do let(:asset) { 'application-6776f581a4329e299531e1d52aa59832.css' } it { is_expected.to eq('application.css') } end context "when asset file path contains 64 chars fingerprint" do let(:asset) { 'application-02275ccb3fd0c11615bbfb11c99ea123ca2287e75045fe7b72cefafb880dad2b.css' } it { is_expected.to eq('application.css') } end context "when asset file page contains numbers, but not a fingerprint" do let(:asset) { 'test/20130708152545-foo-bar.css' } it { is_expected.to eq("test/20130708152545-foo-bar.css") } end end end end premailer-rails-1.12.0/spec/unit/css_loaders/file_system_loader_spec.rb000066400000000000000000000023171433311226200263050ustar00rootroot00000000000000require 'spec_helper' describe Premailer::Rails::CSSLoaders::FileSystemLoader do before do allow(Rails.configuration) .to receive(:assets).and_return(double(prefix: '/assets')) allow(Rails) .to receive(:root).and_return(Pathname.new('/rails_root')) end describe '#file_name' do subject { described_class.file_name(asset) } let(:relative_url_root) { nil } before do config = double(relative_url_root: relative_url_root) allow(Rails).to receive(:configuration).and_return(config) end context 'when relative_url_root is not set' do let(:asset) { '/assets/application.css' } it { is_expected.to eq(File.join(Rails.root, 'public/assets/application.css')) } end context 'when relative_url_root is set' do let(:relative_url_root) { '/foo' } let(:asset) { '/foo/assets/application.css' } it { is_expected.to eq(File.join(Rails.root, 'public/assets/application.css')) } end context 'when relative_url_root has a trailing slash' do let(:relative_url_root) { '/foo/' } let(:asset) { '/foo/assets/application.css' } it { is_expected.to eq(File.join(Rails.root, 'public/assets/application.css')) } end end end premailer-rails-1.12.0/spec/unit/css_loaders/network_loader_spec.rb000066400000000000000000000033641433311226200254560ustar00rootroot00000000000000require 'spec_helper' describe Premailer::Rails::CSSLoaders::NetworkLoader do describe '#uri_for_url' do subject { described_class.uri_for_url(url) } let(:asset_host) { nil } before do action_controller = double(asset_host: asset_host) config = double(action_controller: action_controller) allow(Rails).to receive(:configuration).and_return(config) end context 'with a valid URL' do let(:url) { 'http://example.com/test.css' } it { is_expected.to eq(URI(url)) } end context 'with a protocol relative URL' do let(:url) { '//example.com/test.css' } it { is_expected.to eq(URI("http:#{url}")) } end context 'with a file path' do let(:url) { '/assets/foo.css' } context 'and a domain as asset host' do let(:asset_host) { 'example.com' } it { is_expected.to eq(URI("http://example.com#{url}")) } end context 'and a URL as asset host' do let(:asset_host) { 'https://example.com' } it { is_expected.to eq(URI("https://example.com/assets/foo.css")) } end context 'and a protocol relative URL as asset host' do let(:asset_host) { '//example.com' } it { is_expected.to eq(URI("http://example.com/assets/foo.css")) } end context 'and a callable object as asset host' do let(:asset_host) { double } it 'calls #call with the asset path as argument' do expect(asset_host).to receive(:call).with(url).and_return( 'http://example.com') expect(subject).to eq(URI('http://example.com/assets/foo.css')) end end context 'without an asset host' do let(:asset_host) { nil } it { is_expected.not_to be } end end end end premailer-rails-1.12.0/spec/unit/css_loaders/propshaft_loader_spec.rb000066400000000000000000000035541433311226200257740ustar00rootroot00000000000000require 'spec_helper' if defined?(::Propshaft) describe Premailer::Rails::CSSLoaders::PropshaftLoader do before do allow(Rails.application) .to receive(:assets).and_return(double(prefix: '/assets')) allow(Rails.configuration).to receive(:relative_url_root).and_return(nil) end describe ".file_name" do subject do described_class.file_name(asset) end context "when asset file path contains prefix" do let(:asset) { '/assets/application.css' } it { is_expected.to eq('application.css') } end context "when asset file path contains prefix and relative_url_root is set" do before do allow(Rails.configuration) .to receive(:relative_url_root).and_return('/foo') end let(:asset) { '/foo/assets/application.css' } it { is_expected.to eq('application.css') } end context "when asset file path contains prefix and relative_url_root is set to root" do before do allow(Rails.configuration) .to receive(:relative_url_root).and_return('/') end let(:asset) { '/assets/application.css' } it { is_expected.to eq('application.css') } end context "when asset file path contains 7 chars fingerprint" do let(:asset) { 'application-1234567.css' } it { is_expected.to eq('application.css') } end context "when asset file path contains 128 chars fingerprint" do let(:asset) { 'application-02275ccb3fd0c11615bbfb11c99ea123ca2287e75045fe7b72cefafb880dad2b.css' } it { is_expected.to eq('application.css') } end context "when asset file page contains numbers, but not a fingerprint" do let(:asset) { 'test/20130708152545-foo-bar.css' } it { is_expected.to eq("test/20130708152545-foo-bar.css") } end end end end premailer-rails-1.12.0/spec/unit/customized_premailer_spec.rb000066400000000000000000000043311433311226200243570ustar00rootroot00000000000000require 'spec_helper' describe Premailer::Rails::CustomizedPremailer do describe '#to_plain_text' do it 'includes the text from the HTML part' do premailer = Premailer::Rails::CustomizedPremailer .new(Fixtures::Message::HTML_PART) expect(premailer.to_plain_text.gsub(/\s/, ' ').strip).to \ eq(Fixtures::Message::TEXT_PART.gsub(/\s/, ' ').strip) end end describe '#to_inline_css' do let(:regex) { %r{

} } context 'when inline CSS block present' do it 'returns the HTML with the CSS inlined' do allow(Premailer::Rails::CSSHelper).to \ receive(:css_for_doc).and_return('p { color: red; }') html = Fixtures::Message::HTML_PART premailer = Premailer::Rails::CustomizedPremailer.new(html) expect(premailer.to_inline_css).to match(regex) end end context 'when CSS is loaded externally' do it 'returns the HTML with the CSS inlined' do html = Fixtures::Message::HTML_PART_WITH_CSS premailer = Premailer::Rails::CustomizedPremailer.new(html) expect(premailer.to_inline_css).to match(regex) end end context 'when HTML contains unicode' do it 'does not mess those up' do html = Fixtures::Message::HTML_PART_WITH_UNICODE premailer = Premailer::Rails::CustomizedPremailer.new(html) expect(premailer.to_inline_css).to \ include(Fixtures::Message::UNICODE_STRING) end end end describe '.new' do it 'extracts the CSS' do expect(Premailer::Rails::CSSHelper).to receive(:css_for_doc) Premailer::Rails::CustomizedPremailer.new('some html') end it 'passes on the configs' do Premailer::Rails.config.merge!(foo: :bar) premailer = Premailer::Rails::CustomizedPremailer.new('some html') expect(premailer.instance_variable_get(:'@options')[:foo]).to eq(:bar) end it 'does not allow to override with_html_string' do Premailer::Rails.config.merge!(with_html_string: false) premailer = Premailer::Rails::CustomizedPremailer.new('some html') options = premailer.instance_variable_get(:'@options') expect(options[:with_html_string]).to eq(true) end end end premailer-rails-1.12.0/spec/unit/premailer_rails_spec.rb000066400000000000000000000007021433311226200233010ustar00rootroot00000000000000require 'spec_helper' describe Premailer::Rails do describe '#config' do subject { Premailer::Rails.config } context 'when set' do around do |example| begin default_config = described_class.config described_class.config = { foo: :bar } example.run ensure described_class.config = default_config end end it { is_expected.to eq(foo: :bar) } end end end