schleuder 3.5.3 → 3.6.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
 - data/README.md +6 -5
 - data/Rakefile +3 -1
 - data/db/migrate/20200118170110_add_set_reply_to_to_sender_and_munge_from.rb +15 -0
 - data/db/schema.rb +3 -1
 - data/etc/list-defaults.yml +18 -0
 - data/lib/schleuder/conf.rb +7 -1
 - data/lib/schleuder/list.rb +17 -1
 - data/lib/schleuder/mail/message.rb +83 -9
 - data/lib/schleuder/subscription.rb +27 -4
 - data/lib/schleuder/version.rb +1 -1
 - data/locales/de.yml +1 -0
 - data/locales/en.yml +1 -0
 - metadata +3 -2
 
    
        checksums.yaml
    CHANGED
    
    | 
         @@ -1,7 +1,7 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            ---
         
     | 
| 
       2 
2 
     | 
    
         
             
            SHA256:
         
     | 
| 
       3 
     | 
    
         
            -
              metadata.gz:  
     | 
| 
       4 
     | 
    
         
            -
              data.tar.gz:  
     | 
| 
      
 3 
     | 
    
         
            +
              metadata.gz: 648f81aa424a3214a9d03fb66e5b3e216c8990e092d1b5b18ab41a1f0a1e5fd3
         
     | 
| 
      
 4 
     | 
    
         
            +
              data.tar.gz: 62a5a77189860b4228a2168690f3990d02e53ee4dfb6c458a0273b5407e8a2e7
         
     | 
| 
       5 
5 
     | 
    
         
             
            SHA512:
         
     | 
| 
       6 
     | 
    
         
            -
              metadata.gz:  
     | 
| 
       7 
     | 
    
         
            -
              data.tar.gz:  
     | 
| 
      
 6 
     | 
    
         
            +
              metadata.gz: 97a79b18f6655bd6f9c56beded7527e061fd955433ac2e436a28176eef9d8903916b16a1b0ee22a51f600fbd56d4639b5fadd5a53f3df08d4ca156fc805c9cbb
         
     | 
| 
      
 7 
     | 
    
         
            +
              data.tar.gz: 6e6b4ea2847974d64a3b38a0d99ec0bfa5bb824a36d566fa731889a711b88f127ad6314f9f44b8dd99937977dc0f9d9f2530419762fae527bb24e37b10517343
         
     | 
    
        data/README.md
    CHANGED
    
    | 
         @@ -15,6 +15,7 @@ Requirements 
     | 
|
| 
       15 
15 
     | 
    
         
             
            * gpgme
         
     | 
| 
       16 
16 
     | 
    
         
             
            * sqlite3
         
     | 
| 
       17 
17 
     | 
    
         
             
            * openssl
         
     | 
| 
      
 18 
     | 
    
         
            +
            * icu
         
     | 
| 
       18 
19 
     | 
    
         | 
| 
       19 
20 
     | 
    
         
             
            *If you use Debian buster or CentOS 7, please have a look at the [installation docs](https://schleuder.org/schleuder/docs/server-admins.html#installation). We do provide packages for those platforms, which simplify the installation a lot.*
         
     | 
| 
       20 
21 
     | 
    
         | 
| 
         @@ -22,7 +23,7 @@ Requirements 
     | 
|
| 
       22 
23 
     | 
    
         | 
| 
       23 
24 
     | 
    
         
             
            On systems that base on Debian 10 ("buster"), install the dependencies via
         
     | 
| 
       24 
25 
     | 
    
         | 
| 
       25 
     | 
    
         
            -
                apt-get install ruby-dev gnupg2 libgpgme-dev libsqlite3-dev libssl-dev build-essential
         
     | 
| 
      
 26 
     | 
    
         
            +
                apt-get install ruby-dev gnupg2 libgpgme-dev libsqlite3-dev libssl-dev build-essential libicu-dev
         
     | 
| 
       26 
27 
     | 
    
         | 
| 
       27 
28 
     | 
    
         | 
| 
       28 
29 
     | 
    
         
             
            We **recommend** to also run a random number generator like [haveged](http://www.issihosts.com/haveged/). This ensures Schleuder won't be blocked by lacking entropy, which otherwise might happen especially during key generation.
         
     | 
| 
         @@ -47,15 +48,15 @@ Additionally these **rubygems** are required (will be installed automatically un 
     | 
|
| 
       47 
48 
     | 
    
         
             
            Installing Schleuder
         
     | 
| 
       48 
49 
     | 
    
         
             
            ------------
         
     | 
| 
       49 
50 
     | 
    
         | 
| 
       50 
     | 
    
         
            -
            1. Download [the gem](https://schleuder.org/download/schleuder-3. 
     | 
| 
      
 51 
     | 
    
         
            +
            1. Download [the gem](https://schleuder.org/download/schleuder-3.6.0.gem) and [the OpenPGP-signature](https://schleuder.org/download/schleuder-3.6.0.gem.sig) and verify:
         
     | 
| 
       51 
52 
     | 
    
         
             
               ```
         
     | 
| 
       52 
53 
     | 
    
         
             
               gpg --recv-key 0xB3D190D5235C74E1907EACFE898F2C91E2E6E1F3
         
     | 
| 
       53 
     | 
    
         
            -
               gpg --verify schleuder-3. 
     | 
| 
      
 54 
     | 
    
         
            +
               gpg --verify schleuder-3.6.0.gem.sig
         
     | 
| 
       54 
55 
     | 
    
         
             
               ```
         
     | 
| 
       55 
56 
     | 
    
         | 
| 
       56 
57 
     | 
    
         
             
            2. If all went well install the gem:
         
     | 
| 
       57 
58 
     | 
    
         
             
               ```
         
     | 
| 
       58 
     | 
    
         
            -
               gem install schleuder-3. 
     | 
| 
      
 59 
     | 
    
         
            +
               gem install schleuder-3.6.0.gem
         
     | 
| 
       59 
60 
     | 
    
         
             
               ```
         
     | 
| 
       60 
61 
     | 
    
         | 
| 
       61 
62 
     | 
    
         
             
            3. Set up schleuder:
         
     | 
| 
         @@ -145,4 +146,4 @@ GNU GPL 3.0. Please see [LICENSE.txt](LICENSE.txt). 
     | 
|
| 
       145 
146 
     | 
    
         
             
            Alternative Download
         
     | 
| 
       146 
147 
     | 
    
         
             
            --------------------
         
     | 
| 
       147 
148 
     | 
    
         | 
| 
       148 
     | 
    
         
            -
            Alternatively to the gem-files you can download the latest release as [a tarball](https://schleuder.org/download/schleuder-3. 
     | 
| 
      
 149 
     | 
    
         
            +
            Alternatively to the gem-files you can download the latest release as [a tarball](https://schleuder.org/download/schleuder-3.6.0.tar.gz) and [its OpenPGP-signature](https://schleuder.org/download/schleuder-3.6.0.tar.gz.sig).
         
     | 
    
        data/Rakefile
    CHANGED
    
    | 
         @@ -9,6 +9,8 @@ require_relative "lib/#{project}.rb" 
     | 
|
| 
       9 
9 
     | 
    
         | 
| 
       10 
10 
     | 
    
         
             
            load "active_record/railties/databases.rake"
         
     | 
| 
       11 
11 
     | 
    
         | 
| 
      
 12 
     | 
    
         
            +
            puts @filename_gem
         
     | 
| 
      
 13 
     | 
    
         
            +
             
     | 
| 
       12 
14 
     | 
    
         
             
            # Configure ActiveRecord
         
     | 
| 
       13 
15 
     | 
    
         
             
            ActiveRecord::Tasks::DatabaseTasks.tap do |config|
         
     | 
| 
       14 
16 
     | 
    
         
             
              config.root = File.dirname(__FILE__)
         
     | 
| 
         @@ -89,7 +91,7 @@ end 
     | 
|
| 
       89 
91 
     | 
    
         | 
| 
       90 
92 
     | 
    
         
             
            desc 'OpenPGP-sign gem and tarball'
         
     | 
| 
       91 
93 
     | 
    
         
             
            task :sign_tarball do
         
     | 
| 
       92 
     | 
    
         
            -
              `gpg -u #{@gpguid} -b #{@filename_tarball}`
         
     | 
| 
      
 94 
     | 
    
         
            +
              `gpg -v -u #{@gpguid} -b #{@filename_tarball}`
         
     | 
| 
       93 
95 
     | 
    
         
             
            end
         
     | 
| 
       94 
96 
     | 
    
         | 
| 
       95 
97 
     | 
    
         
             
            desc 'OpenPGP-sign gem'
         
     | 
| 
         @@ -0,0 +1,15 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            class AddSetReplyToToSenderAndMungeFrom < ActiveRecord::Migration
         
     | 
| 
      
 2 
     | 
    
         
            +
              def up
         
     | 
| 
      
 3 
     | 
    
         
            +
                if ! column_exists?(:lists, :set_reply_to_to_sender)
         
     | 
| 
      
 4 
     | 
    
         
            +
                  add_column :lists, :set_reply_to_to_sender, :boolean, default: false
         
     | 
| 
      
 5 
     | 
    
         
            +
                end
         
     | 
| 
      
 6 
     | 
    
         
            +
                if ! column_exists?(:lists, :munge_from)
         
     | 
| 
      
 7 
     | 
    
         
            +
                  add_column :lists, :munge_from, :boolean, default: false
         
     | 
| 
      
 8 
     | 
    
         
            +
                end
         
     | 
| 
      
 9 
     | 
    
         
            +
              end
         
     | 
| 
      
 10 
     | 
    
         
            +
             
     | 
| 
      
 11 
     | 
    
         
            +
              def down
         
     | 
| 
      
 12 
     | 
    
         
            +
                remove_column(:lists, :set_reply_to_to_sender)
         
     | 
| 
      
 13 
     | 
    
         
            +
                remove_column(:lists, :munge_from)
         
     | 
| 
      
 14 
     | 
    
         
            +
              end
         
     | 
| 
      
 15 
     | 
    
         
            +
            end
         
     | 
    
        data/db/schema.rb
    CHANGED
    
    | 
         @@ -11,7 +11,7 @@ 
     | 
|
| 
       11 
11 
     | 
    
         
             
            #
         
     | 
| 
       12 
12 
     | 
    
         
             
            # It's strongly recommended that you check this file into your version control system.
         
     | 
| 
       13 
13 
     | 
    
         | 
| 
       14 
     | 
    
         
            -
            ActiveRecord::Schema.define(version:  
     | 
| 
      
 14 
     | 
    
         
            +
            ActiveRecord::Schema.define(version: 20200118170110) do
         
     | 
| 
       15 
15 
     | 
    
         | 
| 
       16 
16 
     | 
    
         
             
              create_table "lists", force: :cascade do |t|
         
     | 
| 
       17 
17 
     | 
    
         
             
                t.datetime "created_at"
         
     | 
| 
         @@ -46,6 +46,8 @@ ActiveRecord::Schema.define(version: 20190906194820) do 
     | 
|
| 
       46 
46 
     | 
    
         
             
                t.integer  "logfiles_to_keep",                                        default: 2
         
     | 
| 
       47 
47 
     | 
    
         
             
                t.text     "internal_footer",                                         default: ""
         
     | 
| 
       48 
48 
     | 
    
         
             
                t.boolean  "include_autocrypt_header",                                default: true
         
     | 
| 
      
 49 
     | 
    
         
            +
                t.boolean  "set_reply_to_to_sender",                                  default: false
         
     | 
| 
      
 50 
     | 
    
         
            +
                t.boolean  "munge_from",                                              default: false
         
     | 
| 
       49 
51 
     | 
    
         
             
              end
         
     | 
| 
       50 
52 
     | 
    
         | 
| 
       51 
53 
     | 
    
         
             
              create_table "subscriptions", force: :cascade do |t|
         
     | 
    
        data/etc/list-defaults.yml
    CHANGED
    
    | 
         @@ -131,3 +131,21 @@ forward_all_incoming_to_admins: false 
     | 
|
| 
       131 
131 
     | 
    
         
             
            # Disabling this only works for signed e-mails; any e-mail that is unsigned
         
     | 
| 
       132 
132 
     | 
    
         
             
            # sent to the list is treated as coming from an unknown source
         
     | 
| 
       133 
133 
     | 
    
         
             
            deliver_selfsent: true
         
     | 
| 
      
 134 
     | 
    
         
            +
             
     | 
| 
      
 135 
     | 
    
         
            +
            # Set reply-to header to original sender's reply-to? 
         
     | 
| 
      
 136 
     | 
    
         
            +
            # Enabling this will set the reply-to-header of emails sent by schleuder
         
     | 
| 
      
 137 
     | 
    
         
            +
            # to the original sender's reply-to-header. If the original sender
         
     | 
| 
      
 138 
     | 
    
         
            +
            # did not supply a reply-to-header, the original from-header will be used.
         
     | 
| 
      
 139 
     | 
    
         
            +
            # This option can enabled for improved usability since this affect
         
     | 
| 
      
 140 
     | 
    
         
            +
            # mail client's reply-to button to reply to the original sender instead of
         
     | 
| 
      
 141 
     | 
    
         
            +
            # the whole list.
         
     | 
| 
      
 142 
     | 
    
         
            +
            set_reply_to_to_sender: false
         
     | 
| 
      
 143 
     | 
    
         
            +
             
     | 
| 
      
 144 
     | 
    
         
            +
            # Munge from-header?
         
     | 
| 
      
 145 
     | 
    
         
            +
            # Enabling this option will add the original sender to the from-header.
         
     | 
| 
      
 146 
     | 
    
         
            +
            # To avoid DMARC issues, we still use the list's address as from-address.
         
     | 
| 
      
 147 
     | 
    
         
            +
            # However the sender's address will be included as displayed name.
         
     | 
| 
      
 148 
     | 
    
         
            +
            # For example: "sender@sender.org via list@list.org" <list@list.org>
         
     | 
| 
      
 149 
     | 
    
         
            +
            # This option can enabled for improved usability since this affect
         
     | 
| 
      
 150 
     | 
    
         
            +
            # mail client's displayed name.
         
     | 
| 
      
 151 
     | 
    
         
            +
            munge_from: false
         
     | 
    
        data/lib/schleuder/conf.rb
    CHANGED
    
    | 
         @@ -4,7 +4,13 @@ module Schleuder 
     | 
|
| 
       4 
4 
     | 
    
         
             
              class Conf
         
     | 
| 
       5 
5 
     | 
    
         
             
                include Singleton
         
     | 
| 
       6 
6 
     | 
    
         | 
| 
       7 
     | 
    
         
            -
                 
     | 
| 
      
 7 
     | 
    
         
            +
                # since the regexp got only included into stdlib 2.2
         
     | 
| 
      
 8 
     | 
    
         
            +
                # TODO: remove once 2.1 support dropped
         
     | 
| 
      
 9 
     | 
    
         
            +
                if RUBY_VERSION < '2.2'
         
     | 
| 
      
 10 
     | 
    
         
            +
                  EMAIL_REGEXP = /\A[a-zA-Z0-9.!\#$%&'*+\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*\z/
         
     | 
| 
      
 11 
     | 
    
         
            +
                else
         
     | 
| 
      
 12 
     | 
    
         
            +
                  EMAIL_REGEXP = URI::MailTo::EMAIL_REGEXP
         
     | 
| 
      
 13 
     | 
    
         
            +
                end
         
     | 
| 
       8 
14 
     | 
    
         
             
                # TODO: drop v3 keys and only accept length of 40
         
     | 
| 
       9 
15 
     | 
    
         
             
                FINGERPRINT_REGEXP = /\A(0x)?[a-f0-9]{32}([a-f0-9]{8})?\z/i
         
     | 
| 
       10 
16 
     | 
    
         | 
    
        data/lib/schleuder/list.rb
    CHANGED
    
    | 
         @@ -67,6 +67,22 @@ module Schleuder 
     | 
|
| 
       67 
67 
     | 
    
         
             
                            with: /\A[[:graph:]\s]*\z/i,
         
     | 
| 
       68 
68 
     | 
    
         
             
                          }
         
     | 
| 
       69 
69 
     | 
    
         | 
| 
      
 70 
     | 
    
         
            +
                # Some users find it quite confusing when they click "reply-to" and the mail client 
         
     | 
| 
      
 71 
     | 
    
         
            +
                # doesn't reply to the sender of the mail but the whole mailing list. For those lists it can be
         
     | 
| 
      
 72 
     | 
    
         
            +
                # considered to set this value to true. The recipients will then receive e-mails
         
     | 
| 
      
 73 
     | 
    
         
            +
                # where the "reply-to" header will contain the reply-to address
         
     | 
| 
      
 74 
     | 
    
         
            +
                # of the sender and thus reply to the sender when clicking "reply-to" in a client.
         
     | 
| 
      
 75 
     | 
    
         
            +
                # If no "reply-to" is set, the "from"-header of the original sender will be used.
         
     | 
| 
      
 76 
     | 
    
         
            +
                # The default is off.
         
     | 
| 
      
 77 
     | 
    
         
            +
                validates :set_reply_to_to_sender, boolean: true
         
     | 
| 
      
 78 
     | 
    
         
            +
             
     | 
| 
      
 79 
     | 
    
         
            +
                # Some users find it confusing when the "from" does not contain the original sender
         
     | 
| 
      
 80 
     | 
    
         
            +
                # but the list address. For those lists it can be considered to set the munged header.
         
     | 
| 
      
 81 
     | 
    
         
            +
                # This will result in a "from"-header like this: "originalsender@original.com via list@list.com"
         
     | 
| 
      
 82 
     | 
    
         
            +
                # The default is off.
         
     | 
| 
      
 83 
     | 
    
         
            +
                validates :munge_from, boolean: true
         
     | 
| 
      
 84 
     | 
    
         
            +
             
     | 
| 
      
 85 
     | 
    
         
            +
             
     | 
| 
       70 
86 
     | 
    
         
             
                default_scope { order(:email) }
         
     | 
| 
       71 
87 
     | 
    
         | 
| 
       72 
88 
     | 
    
         
             
                def self.configurable_attributes
         
     | 
| 
         @@ -367,7 +383,7 @@ module Schleuder 
     | 
|
| 
       367 
383 
     | 
    
         
             
                        next
         
     | 
| 
       368 
384 
     | 
    
         
             
                      end
         
     | 
| 
       369 
385 
     | 
    
         | 
| 
       370 
     | 
    
         
            -
                      subscription.send_mail(mail)
         
     | 
| 
      
 386 
     | 
    
         
            +
                      subscription.send_mail(mail, incoming_mail)
         
     | 
| 
       371 
387 
     | 
    
         | 
| 
       372 
388 
     | 
    
         
             
                    rescue => exc
         
     | 
| 
       373 
389 
     | 
    
         
             
                      msg = I18n.t('errors.delivery_error',
         
     | 
| 
         @@ -205,17 +205,17 @@ module Mail 
     | 
|
| 
       205 
205 
     | 
    
         
             
                  @recipient.match(/-bounce@/).present? ||
         
     | 
| 
       206 
206 
     | 
    
         
             
                      # Empty Return-Path
         
     | 
| 
       207 
207 
     | 
    
         
             
                      self.return_path.to_s == '<>' ||
         
     | 
| 
       208 
     | 
    
         
            -
                       
     | 
| 
       209 
     | 
    
         
            -
                      #  - no cron header is present
         
     | 
| 
       210 
     | 
    
         
            -
                      #  - no Jenkins job notification header is present
         
     | 
| 
       211 
     | 
    
         
            -
                      # as these emails have the auto-submitted header.
         
     | 
| 
       212 
     | 
    
         
            -
                      ( self['Auto-Submitted'].present? && \
         
     | 
| 
       213 
     | 
    
         
            -
                        self['Auto-Submitted'].to_s.downcase != 'no' && \
         
     | 
| 
       214 
     | 
    
         
            -
                        !self['X-Cron-Env'].present? && \
         
     | 
| 
       215 
     | 
    
         
            -
                        !self['X-Jenkins-Job'].present? && \
         
     | 
| 
       216 
     | 
    
         
            -
                        self.subject.to_s !~ /\A\*\*\* SECURITY information.*\*\*\*\Z/)
         
     | 
| 
      
 208 
     | 
    
         
            +
                      bounced?
         
     | 
| 
       217 
209 
     | 
    
         
             
                end
         
     | 
| 
       218 
210 
     | 
    
         | 
| 
      
 211 
     | 
    
         
            +
                def bounced?
         
     | 
| 
      
 212 
     | 
    
         
            +
                  @bounced ||= bounce_detected? || (error_status != "unknown")
         
     | 
| 
      
 213 
     | 
    
         
            +
                end
         
     | 
| 
      
 214 
     | 
    
         
            +
             
     | 
| 
      
 215 
     | 
    
         
            +
                def error_status
         
     | 
| 
      
 216 
     | 
    
         
            +
                  @error_status ||= detect_error_code
         
     | 
| 
      
 217 
     | 
    
         
            +
                end
         
     | 
| 
      
 218 
     | 
    
         
            +
             
         
     | 
| 
       219 
219 
     | 
    
         
             
                def keywords
         
     | 
| 
       220 
220 
     | 
    
         
             
                  return @keywords if @keywords
         
     | 
| 
       221 
221 
     | 
    
         | 
| 
         @@ -526,5 +526,79 @@ module Mail 
     | 
|
| 
       526 
526 
     | 
    
         
             
                    end
         
     | 
| 
       527 
527 
     | 
    
         
             
                  end.join(' ')
         
     | 
| 
       528 
528 
     | 
    
         
             
                end
         
     | 
| 
      
 529 
     | 
    
         
            +
             
     | 
| 
      
 530 
     | 
    
         
            +
                def detect_error_code
         
     | 
| 
      
 531 
     | 
    
         
            +
                  # Detects the error code of an email with different heuristics
         
     | 
| 
      
 532 
     | 
    
         
            +
                  # from: https://github.com/mailtop/bounce_email
         
     | 
| 
      
 533 
     | 
    
         
            +
                  
         
     | 
| 
      
 534 
     | 
    
         
            +
                  # Custom status codes
         
     | 
| 
      
 535 
     | 
    
         
            +
                  unicode_subject = self.subject.to_s
         
     | 
| 
      
 536 
     | 
    
         
            +
                  unicode_subject = unicode_subject.encode('utf-8') if unicode_subject.respond_to?(:encode)
         
     | 
| 
      
 537 
     | 
    
         
            +
             
         
     | 
| 
      
 538 
     | 
    
         
            +
                  return '97' if unicode_subject.match(/delayed/i)
         
     | 
| 
      
 539 
     | 
    
         
            +
                  return '98' if unicode_subject.match(/(unzulässiger|unerlaubter) anhang/i)
         
     | 
| 
      
 540 
     | 
    
         
            +
                  return '99' if unicode_subject.match(/auto.*reply|férias|ferias|Estarei ausente|estou ausente|vacation|vocation|(out|away).*office|on holiday|abwesenheits|autorespond|Automatische|eingangsbestätigung/i)
         
     | 
| 
      
 541 
     | 
    
         
            +
             
     | 
| 
      
 542 
     | 
    
         
            +
                  # Feedback-Type: abuse
         
     | 
| 
      
 543 
     | 
    
         
            +
                  return '96' if self.to_s.match(/Feedback-Type\: abuse/i)
         
     | 
| 
      
 544 
     | 
    
         
            +
             
     | 
| 
      
 545 
     | 
    
         
            +
                  if self.parts[1]
         
     | 
| 
      
 546 
     | 
    
         
            +
                    match_parts = self.parts[1].body.match(/(Status:.|550 |#)([245]\.[0-9]{1,3}\.[0-9]{1,3})/)
         
     | 
| 
      
 547 
     | 
    
         
            +
                    code = match_parts[2] if match_parts
         
     | 
| 
      
 548 
     | 
    
         
            +
                    return code if code
         
     | 
| 
      
 549 
     | 
    
         
            +
                  end
         
     | 
| 
      
 550 
     | 
    
         
            +
             
     | 
| 
      
 551 
     | 
    
         
            +
                  # Now try getting it from correct part of tmail
         
     | 
| 
      
 552 
     | 
    
         
            +
                  code = detect_bounce_status_code_from_text(self.body)
         
     | 
| 
      
 553 
     | 
    
         
            +
                  return code if code
         
     | 
| 
      
 554 
     | 
    
         
            +
             
     | 
| 
      
 555 
     | 
    
         
            +
                  # OK getting desperate so try getting code from entire email
         
     | 
| 
      
 556 
     | 
    
         
            +
                  code = detect_bounce_status_code_from_text(self.to_s)
         
     | 
| 
      
 557 
     | 
    
         
            +
                  code || 'unknown'
         
     | 
| 
      
 558 
     | 
    
         
            +
                end
         
     | 
| 
      
 559 
     | 
    
         
            +
             
     | 
| 
      
 560 
     | 
    
         
            +
                def bounce_detected?
         
     | 
| 
      
 561 
     | 
    
         
            +
                  # Detects bounces from different parts of the email without error status codes
         
     | 
| 
      
 562 
     | 
    
         
            +
                  # from: https://github.com/mailtop/bounce_email
         
     | 
| 
      
 563 
     | 
    
         
            +
                  return true if self.subject.to_s.match(/(returned|undelivered) mail|mail delivery( failed)?|(delivery )(status notification|failure)|failure notice|undeliver(able|ed)( mail)?|return(ing message|ed) to sender/i)
         
     | 
| 
      
 564 
     | 
    
         
            +
                  return true if self.subject.to_s.match(/auto.*reply|vacation|vocation|(out|away).*office|on holiday|abwesenheits|autorespond|Automatische|eingangsbestätigung/i)
         
     | 
| 
      
 565 
     | 
    
         
            +
                  return true if self['precedence'].to_s.match(/auto.*(reply|responder|antwort)/i)
         
     | 
| 
      
 566 
     | 
    
         
            +
                  return true if self.from.to_s.match(/^(MAILER-DAEMON|POSTMASTER)\@/i)
         
     | 
| 
      
 567 
     | 
    
         
            +
                  false
         
     | 
| 
      
 568 
     | 
    
         
            +
                end
         
     | 
| 
      
 569 
     | 
    
         
            +
             
     | 
| 
      
 570 
     | 
    
         
            +
                def detect_bounce_status_code_from_text(text)
         
     | 
| 
      
 571 
     | 
    
         
            +
                  # Parses a text and uses pattern matching to determines its error status (RFC 3463)
         
     | 
| 
      
 572 
     | 
    
         
            +
                  # from: https://github.com/mailtop/bounce_email
         
     | 
| 
      
 573 
     | 
    
         
            +
                  return "5.0.0" if text.match(/Status: 5\.0\.0/i)
         
     | 
| 
      
 574 
     | 
    
         
            +
                  return "5.1.1" if text.match(/no such (address|user)|Recipient address rejected|User unknown|does not like recipient|The recipient was unavailable to take delivery of the message|Sorry, no mailbox here by that name|invalid address|unknown user|unknown local part|user not found|invalid recipient|failed after I sent the message|did not reach the following recipient|nicht zugestellt werden|o pode ser entregue para um ou mais/i)
         
     | 
| 
      
 575 
     | 
    
         
            +
                  return "5.1.2" if text.match(/unrouteable mail domain|Esta casilla ha expirado por falta de uso|I couldn't find any host named/i)
         
     | 
| 
      
 576 
     | 
    
         
            +
                  if text.match(/mailbox is full|Mailbox quota (usage|disk) exceeded|quota exceeded|Over quota|User mailbox exceeds allowed size|Message rejected\. Not enough storage space|user has exhausted allowed storage space|too many messages on the server|mailbox is over quota|mailbox exceeds allowed size|excedeu a quota/i)
         
     | 
| 
      
 577 
     | 
    
         
            +
                    return "5.2.2" if text.match(/This is a permanent error||(Status: |)5\.2\.2/i)
         
     | 
| 
      
 578 
     | 
    
         
            +
                    return "4.2.2"
         
     | 
| 
      
 579 
     | 
    
         
            +
                  end
         
     | 
| 
      
 580 
     | 
    
         
            +
                  return "5.1.0" if text.match(/Address rejected/)
         
     | 
| 
      
 581 
     | 
    
         
            +
                  return "4.1.2" if text.match(/I couldn't find any host by that name/)
         
     | 
| 
      
 582 
     | 
    
         
            +
                  return "4.2.0" if text.match(/not yet been delivered/i)
         
     | 
| 
      
 583 
     | 
    
         
            +
                  return "5.1.1" if text.match(/mailbox unavailable|No such mailbox|RecipientNotFound|not found by SMTP address lookup|Status: 5\.1\.1/i)
         
     | 
| 
      
 584 
     | 
    
         
            +
                  return "5.2.3" if text.match(/Status: 5\.2\.3/i) # Too messages in folder
         
     | 
| 
      
 585 
     | 
    
         
            +
                  return "5.4.0" if text.match(/Status: 5\.4\.0/i) # too many hops
         
     | 
| 
      
 586 
     | 
    
         
            +
                  return "5.4.4" if text.match(/Unrouteable address/i)
         
     | 
| 
      
 587 
     | 
    
         
            +
                  return "4.4.7" if text.match(/retry timeout exceeded/i)
         
     | 
| 
      
 588 
     | 
    
         
            +
                  return "5.2.0" if text.match(/The account or domain may not exist, they may be blacklisted, or missing the proper dns entries./i)
         
     | 
| 
      
 589 
     | 
    
         
            +
                  return "5.5.4" if text.match(/554 TRANSACTION FAILED/i)
         
     | 
| 
      
 590 
     | 
    
         
            +
                  return "4.4.1" if text.match(/Status: 4.4.1|delivery temporarily suspended|wasn't able to establish an SMTP connection/i)
         
     | 
| 
      
 591 
     | 
    
         
            +
                  return "5.5.0" if text.match(/550 OU\-002|Mail rejected by Windows Live Hotmail for policy reasons/i)
         
     | 
| 
      
 592 
     | 
    
         
            +
                  return "5.1.2" if text.match(/PERM_FAILURE: DNS Error: Domain name not found/i)
         
     | 
| 
      
 593 
     | 
    
         
            +
                  return "4.2.0" if text.match(/Delivery attempts will continue to be made for/i)
         
     | 
| 
      
 594 
     | 
    
         
            +
                  return "5.5.4" if text.match(/554 delivery error:/i)
         
     | 
| 
      
 595 
     | 
    
         
            +
                  return "5.1.1" if text.match(/550-5.1.1|This Gmail user does not exist/i)
         
     | 
| 
      
 596 
     | 
    
         
            +
                  return "5.7.1" if text.match(/5.7.1 Your message.*?was blocked by ROTA DNSBL/i) # AA added
         
     | 
| 
      
 597 
     | 
    
         
            +
                  return "5.7.2" if text.match(/not have permission to post messages to the group/i)
         
     | 
| 
      
 598 
     | 
    
         
            +
                  return "5.3.2" if text.match(/Technical details of permanent failure|Too many bad recipients/i) && (text.match(/The recipient server did not accept our requests to connect/i) || text.match(/Connection was dropped by remote host/i) || text.match(/Could not initiate SMTP conversation/i)) # AA added
         
     | 
| 
      
 599 
     | 
    
         
            +
                  return "4.3.2" if text.match(/Technical details of temporary failure/i) && (text.match(/The recipient server did not accept our requests to connect/i) || text.match(/Connection was dropped by remote host/i) || text.match(/Could not initiate SMTP conversation/i)) # AA added
         
     | 
| 
      
 600 
     | 
    
         
            +
                  return "5.0.0" if text.match(/Delivery to the following recipient failed permanently/i) # AA added
         
     | 
| 
      
 601 
     | 
    
         
            +
                  return '5.2.3' if text.match(/account closed|account has been disabled or discontinued|mailbox not found|prohibited by administrator|access denied|account does not exist/i)
         
     | 
| 
      
 602 
     | 
    
         
            +
                end
         
     | 
| 
       529 
603 
     | 
    
         
             
              end
         
     | 
| 
       530 
604 
     | 
    
         
             
            end
         
     | 
| 
         @@ -10,6 +10,10 @@ module Schleuder 
     | 
|
| 
       10 
10 
     | 
    
         
             
                validates :fingerprint, allow_blank: true, fingerprint: true
         
     | 
| 
       11 
11 
     | 
    
         
             
                validates :delivery_enabled, :admin, boolean: true
         
     | 
| 
       12 
12 
     | 
    
         | 
| 
      
 13 
     | 
    
         
            +
                before_validation {
         
     | 
| 
      
 14 
     | 
    
         
            +
                  self.email = Mail::Address.new(self.email).address
         
     | 
| 
      
 15 
     | 
    
         
            +
                }
         
     | 
| 
      
 16 
     | 
    
         
            +
             
     | 
| 
       13 
17 
     | 
    
         
             
                default_scope { order(:email) }
         
     | 
| 
       14 
18 
     | 
    
         | 
| 
       15 
19 
     | 
    
         
             
                scope :without_fingerprint, -> { where(fingerprint: [nil,'']) }
         
     | 
| 
         @@ -37,10 +41,10 @@ module Schleuder 
     | 
|
| 
       37 
41 
     | 
    
         
             
                  list.keys("0x#{self.fingerprint}").first
         
     | 
| 
       38 
42 
     | 
    
         
             
                end
         
     | 
| 
       39 
43 
     | 
    
         | 
| 
       40 
     | 
    
         
            -
                def send_mail(mail)
         
     | 
| 
      
 44 
     | 
    
         
            +
                def send_mail(mail, incoming_mail=nil)
         
     | 
| 
       41 
45 
     | 
    
         
             
                  list.logger.debug "Preparing sending to #{self.inspect}"
         
     | 
| 
       42 
46 
     | 
    
         | 
| 
       43 
     | 
    
         
            -
                  mail = ensure_headers(mail)
         
     | 
| 
      
 47 
     | 
    
         
            +
                  mail = ensure_headers(mail, incoming_mail)
         
     | 
| 
       44 
48 
     | 
    
         
             
                  gpg_opts = self.list.gpg_sign_options
         
     | 
| 
       45 
49 
     | 
    
         | 
| 
       46 
50 
     | 
    
         
             
                  if self.key.blank?
         
     | 
| 
         @@ -66,9 +70,28 @@ module Schleuder 
     | 
|
| 
       66 
70 
     | 
    
         
             
                  mail.deliver
         
     | 
| 
       67 
71 
     | 
    
         
             
                end
         
     | 
| 
       68 
72 
     | 
    
         | 
| 
       69 
     | 
    
         
            -
                def ensure_headers(mail)
         
     | 
| 
      
 73 
     | 
    
         
            +
                def ensure_headers(mail, incoming_mail=nil)
         
     | 
| 
       70 
74 
     | 
    
         
             
                  mail.to = self.email
         
     | 
| 
       71 
     | 
    
         
            -
                   
     | 
| 
      
 75 
     | 
    
         
            +
                  
         
     | 
| 
      
 76 
     | 
    
         
            +
                  if self.list.set_reply_to_to_sender? && ! incoming_mail.nil?
         
     | 
| 
      
 77 
     | 
    
         
            +
                    # If the option "set_reply_to_to_sender" is set to true, we will set the reply-to header 
         
     | 
| 
      
 78 
     | 
    
         
            +
                    # to the reply-to header given by the original email. If no reply-to header exists in the original email,
         
     | 
| 
      
 79 
     | 
    
         
            +
                    # the original senders email will be used as reply-to.
         
     | 
| 
      
 80 
     | 
    
         
            +
                    if ! incoming_mail.reply_to.nil?
         
     | 
| 
      
 81 
     | 
    
         
            +
                      mail.reply_to = incoming_mail.reply_to
         
     | 
| 
      
 82 
     | 
    
         
            +
                    else
         
     | 
| 
      
 83 
     | 
    
         
            +
                      mail.reply_to = incoming_mail.from
         
     | 
| 
      
 84 
     | 
    
         
            +
                    end
         
     | 
| 
      
 85 
     | 
    
         
            +
                  end
         
     | 
| 
      
 86 
     | 
    
         
            +
             
     | 
| 
      
 87 
     | 
    
         
            +
                  if self.list.munge_from? && ! incoming_mail.nil? 
         
     | 
| 
      
 88 
     | 
    
         
            +
                    # If the option "munge_from" is set to true, we will add the original senders' from-header to ours.
         
     | 
| 
      
 89 
     | 
    
         
            +
                    # We munge the from-header to avoid issues with DMARC.
         
     | 
| 
      
 90 
     | 
    
         
            +
                    mail.from = I18n.t("header_munging", from: incoming_mail.from.first, list: self.list.email, list_address: self.list.email)
         
     | 
| 
      
 91 
     | 
    
         
            +
                  else
         
     | 
| 
      
 92 
     | 
    
         
            +
                    mail.from = self.list.email
         
     | 
| 
      
 93 
     | 
    
         
            +
                  end
         
     | 
| 
      
 94 
     | 
    
         
            +
             
     | 
| 
       72 
95 
     | 
    
         
             
                  mail.sender = self.list.bounce_address
         
     | 
| 
       73 
96 
     | 
    
         
             
                  mail
         
     | 
| 
       74 
97 
     | 
    
         
             
                end
         
     | 
    
        data/lib/schleuder/version.rb
    CHANGED
    
    
    
        data/locales/de.yml
    CHANGED
    
    
    
        data/locales/en.yml
    CHANGED
    
    
    
        metadata
    CHANGED
    
    | 
         @@ -1,14 +1,14 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            --- !ruby/object:Gem::Specification
         
     | 
| 
       2 
2 
     | 
    
         
             
            name: schleuder
         
     | 
| 
       3 
3 
     | 
    
         
             
            version: !ruby/object:Gem::Version
         
     | 
| 
       4 
     | 
    
         
            -
              version: 3. 
     | 
| 
      
 4 
     | 
    
         
            +
              version: 3.6.0
         
     | 
| 
       5 
5 
     | 
    
         
             
            platform: ruby
         
     | 
| 
       6 
6 
     | 
    
         
             
            authors:
         
     | 
| 
       7 
7 
     | 
    
         
             
            - schleuder dev team
         
     | 
| 
       8 
8 
     | 
    
         
             
            autorequire: 
         
     | 
| 
       9 
9 
     | 
    
         
             
            bindir: bin
         
     | 
| 
       10 
10 
     | 
    
         
             
            cert_chain: []
         
     | 
| 
       11 
     | 
    
         
            -
            date:  
     | 
| 
      
 11 
     | 
    
         
            +
            date: 2021-02-07 00:00:00.000000000 Z
         
     | 
| 
       12 
12 
     | 
    
         
             
            dependencies:
         
     | 
| 
       13 
13 
     | 
    
         
             
            - !ruby/object:Gem::Dependency
         
     | 
| 
       14 
14 
     | 
    
         
             
              name: gpgme
         
     | 
| 
         @@ -291,6 +291,7 @@ files: 
     | 
|
| 
       291 
291 
     | 
    
         
             
            - db/migrate/20180110203100_add_sig_enc_to_headers_to_meta_defaults.rb
         
     | 
| 
       292 
292 
     | 
    
         
             
            - db/migrate/20180723173900_add_deliver_selfsent_to_list.rb
         
     | 
| 
       293 
293 
     | 
    
         
             
            - db/migrate/20190906194820_add_autocrypt_header_to_list.rb
         
     | 
| 
      
 294 
     | 
    
         
            +
            - db/migrate/20200118170110_add_set_reply_to_to_sender_and_munge_from.rb
         
     | 
| 
       294 
295 
     | 
    
         
             
            - db/schema.rb
         
     | 
| 
       295 
296 
     | 
    
         
             
            - etc/init.d/schleuder-api-daemon
         
     | 
| 
       296 
297 
     | 
    
         
             
            - etc/list-defaults.yml
         
     |