Help us understand the problem. What is going on with this article?

Redmineでメールからチケットを作成するときに添付ファイルをエンコード変換せずに保存する

More than 3 years have passed since last update.

Redmineには指定のアドレスに送ったメールからチケットを作ったり、チケットコメントを追記したりする機能があります。そのメールに添付ファイルがある場合は、チケットの添付ファイルにも追加されます。

問題

この添付ファイルがテキストファイルである場合に、文字コードが変わってしまう問題があります。
具体的には、メールにSJISのテキストファイルを添付してRedmineで取り込み、作成されたチケットのページからそのファイルをダウンロードするとファイルのエンコードがUTF-8に変わってしまうことがあります。
添付ファイルは元々のバイナリを維持したままのファイルを保存してほしいところなのですが、この挙動は困ってしまいます。

なお、この問題は必ず起きるわけではありません。メールの生データ中で添付ファイル部分のContent-Typeで「charset」を指定していると、この問題が発生します。
charsetが明記されているために、エンコードができてしまっていることが原因のようです。
メーラによってはここにcharsetを明記しないらしく、Outlookから送ったメールでは問題がおきず、Gmailから送ったメールでは問題がおきました。

問題が起きるメールの添付ファイル部分

--f46d040714391fef6a0510328cb4
Content-Type: text/plain; charset=Shift_JIS; name="text.sjis.txt"
Content-Disposition: attachment; filename="text.sjis.txt"
Content-Transfer-Encoding: base64

CoNUg5ODdoOLg3SDQINDg4tzamlzCgo=

この問題は結構困りそうなのですが、ググった限りではいまいちこの現状について書かれているものがありませんでした。

原因

この問題は、Redmineのメールからチケットを生成する以下の箇所で、attachment.decodedを使っているのが原因のようです。

https://github.com/redmine/redmine/blob/3.0.0/app/models/mail_handler.rb#L282

  def add_attachments(obj)
    if email.attachments && email.attachments.any?
      email.attachments.each do |attachment|
        next unless accept_attachment?(attachment)
        obj.attachments << Attachment.create(:container => obj,
                          :file => attachment.decoded,
                          :filename => attachment.filename,
                          :author => user,
                          :content_type => attachment.mime_type)
      end
    end
  end

ここのdecodedメソッドは、MailモジュールのMessage#decodedメソッドで、内容がテキストファイルの場合にはエンコード変換済みの内容を返してしまいます。
このメソッドの代わりにMessage#readメソッドを使えば、元々のバイナリをそのまま取得できそうです。

対処

修正方法が分かったので、そのモンキーパッチをプラグイン形式にして作成しました。

https://github.com/namutaka/mail-attachments-as-binary

おまけ

ちなみに、Redmineのプラグインは初めて作ったのですが、モンキーパッチをプラグイン化する方法の説明が中々みつからず苦労しました...
以下に公式っぽい文書があるのですが、どうも内容が古いようです。

http://www.redmine.org/projects/redmine/wiki/Plugin_Internals

上記のページで紹介されているinit.rbではDispatcher#to_prepareを使っているのですが、試してみると"dispacher"をrequireできずに使えませんでした。

require 'dispatcher'

Dispatcher.to_prepare :redmine_kanban do
 # パッチ設定
end

その代わりに、Rails.configuration.to_prepareを使っている例があったので、それを参考にしています。

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away