質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
Visual Studio

Microsoft Visual StudioはMicrosoftによる統合開発環境(IDE)です。多種多様なプログラミング言語に対応しています。

MacOS(OSX)

MacOSとは、Appleの開発していたGUI(グラフィカルユーザーインターフェース)を採用したオペレーションシステム(OS)です。Macintoshと共に、市場に出てGUIの普及に大きく貢献しました。

Xamarin

Xamarin(ザマリン)は、iPhoneなどのiOSやAndroidで動作し、C# 言語を用いてアプリを開発できるクロスプラットフォーム開発環境です。Xamarin Studioと C# 言語を用いて、 iOS と Android の両方の開発を行うことができます。

Q&A

解決済

3回答

2112閲覧

Mime規格に則ったメールのsubjectを作成する際に、Base64でエンコードする文字列の途中に記号があると文字列としてデコードされません。

退会済みユーザー

退会済みユーザー

総合スコア0

Visual Studio

Microsoft Visual StudioはMicrosoftによる統合開発環境(IDE)です。多種多様なプログラミング言語に対応しています。

MacOS(OSX)

MacOSとは、Appleの開発していたGUI(グラフィカルユーザーインターフェース)を採用したオペレーションシステム(OS)です。Macintoshと共に、市場に出てGUIの普及に大きく貢献しました。

Xamarin

Xamarin(ザマリン)は、iPhoneなどのiOSやAndroidで動作し、C# 言語を用いてアプリを開発できるクロスプラットフォーム開発環境です。Xamarin Studioと C# 言語を用いて、 iOS と Android の両方の開発を行うことができます。

0グッド

1クリップ

投稿2018/03/02 17:13

編集2018/03/03 15:13

##現状
(頂きました回答を元に、文末に追記致しました)

以下の環境で、メーラーを作成しているのですが。
subjectを作成する際にBase64へUTF-8の文字列をエンコードしています。
エンコードする文字列のなかに記号や半角文字が入った状態でエンコードしメールを送信すると、
受信したメーラーでsubjetがデコードされていない状態になってしまっています。
例と使用環境、現在のコードは以下に記載させていただきます。

何卒、ご教授の程よろしくお願い致します。

##やりたいこと
subjectの文字列がしっかりとデコードされ、文章として読めるようになること。
(今後:文字列はUTF-8だけでなく、ASCIIやShift-JIS、iso-2022-jpなどを用いることも視野に入れています)
(今後:Base64だけでなく、quoted-printableでのエンコードも考えています)

###使用環境
PC:MacOSX
環境:Visual Studio Community 2017 for Mac
言語:c#

###現状
以下のコードでsubjectを作成しています。

c#

1 2string sub = "我輩は猫である。名前はまだ無い。"; 3 4MimeKit.Encodings.Base64Encoder ed = new MimeKit.Encodings.Base64Encoder(); 5System.Text.Encoding charEcd = System.Text.Encoding.UTF8; 6 7sub = sub + "\n\r"; // 何故か末尾1文字が切れてしまうための対策 8byte[] cc = charEcd.GetBytes(sub); 9byte[] nnn = new byte[1000];  // outputされるバイト領域を多めに取っています 10 11ed.Encode(cc, 0, cc.Length, nnn); 12 13string ttt = System.Text.Encoding.UTF8.GetString(nnn); 14m_subject = string.Format("=?{0}?B?{1}?=", charEcd.BodyName, ttt.TrimEnd('\0')); 15 16Mimemes.Headers.Add(HeaderId.Subject, m_subject); 17

上記コード内(1行目)にある文字列が記載されている通りの場合は、以下の画像の成功例のようになります。
しかし、以下のようにすると失敗例の画像のようになってしまいます。

c#

1string sub = "吾輩は猫である。1.2.3.名前はまだ無い。"

どうすればしっかりとデコードされ、受信側メーラーの件名に
「吾輩は猫である。1.2.3.名前はまだ無い。」
と表示されるのでしょうか?

何卒ご教授のほど、よろしくお願い致します。

###成功例と失敗例

①成功例画像
成功例

②失敗例画像
失敗例


##追記(1)
文字列中にCRが混入しているとのコメントを頂き、以下のようにコードを編集致しました。

c#

1string sub = "あいうえおかきくけこさしすせそなにぬねのはひふへほ"; 2 3MimeKit.Encodings.Base64Encoder ed = new MimeKit.Encodings.Base64Encoder(); 4System.Text.Encoding charEcd = System.Text.Encoding.UTF8; 5 6byte[] cc = charEcd.GetBytes(sub); 7byte[] nnn = new byte[1000]; 8ed.Encode(cc, 0, cc.Length, nnn); 9 10byte[] bb = charEcd.GetBytes("\n"); 11byte[] nb = new byte[1000]; 12 13int ii = 0; 14for (int i = 0; i < nnn.Length;i++) 15{ 16 if (nnn[i] != bb[0]) 17 { 18 nb[ii] = nnn[i]; 19 ii = ii + 1; 20 } 21} 22 23string ttt = charEcd.GetString(nb).TrimEnd('\0'); 24m_subject = string.Format("=?{0}?B?{1}?=", charEcd.BodyName, ttt); 25 26

新しく編集したコードでエンコードした文字列は以下となります
(エンコードした文字列はブレークポイントで停止し抽出したエンコードした文字列です)

- 元の文字列:あいうえおかきくけこさしすせそなにぬねのはひふへほ - エンコードした文字列:=?utf-8?B?44GC44GE44GG44GI44GK44GL44GN44GP44GR44GT44GV44GX44GZ44Gb44Gd44Gq44Gr44Gs44Gt44Gu44Gv44Gy44G144G444G7?=

###問題点
ネットなどにあるツールを用いると、元の文字列の通り「あいうえおかきくけこさしすせそなにぬねのはひふへほ」とデコードすることができます。
しかし実際にメールとして送信し、受信メーラー(複数メーラーにて確認済み)しすると、どれもデコードに失敗し、エンコードした文字列のまま表示されてしまっていました。

どのようにしたらメーラーのsubjectでエンコードした文字列を表示できるのでしょうか?

何卒、ご教授をお願い致します。

###試したこと
エンコードした文字列が長すぎるのかとも思い、以下のように複数行へエンコードも実践致しました。

=?utf-8?B?44GC44GE44GG44GI44GK44GL44GN44GP44GR44GT44GV44GX44GZ44Gb44Gd?= =?utf-8?B?44Gq44Gr44Gs44Gt44Gu44Gv44Gy44G144G444G7?=

しかし結果は問題点同様の結果しか得ることができませんでした。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答3

0

ベストアンサー

先日別の質問で提示させて頂いた、MimeKit/Rfc2047.csを一読されるようお勧めします。
EncodePhrase() または EncodeText()
-> Encode()
-> AppendEncodedWord()
あたりの流れが参考になると思います。

AppendEncodedWord()では、942行目の

if (CharsetRequiresBase64 (charset) || GetBestContentEncoding (word, 0, len) == ContentEncoding.Base64) {

でBase64/Quoted-printableを切り替えています。

これらの情報を参考に、必要な部分を抜き出せばやりたいことは実現出来ると思います。
(GetBestContentEncoding()の戻り値相当を、変更or指定出来れば良いのですが……)


検証に使えるsmtpサーバが無かったので、smtp4devを使って確認してみました。

C#

1 var subject = "吾輩は猫である。1.2.3.名前はまだ無い。"; 2 var encoded = Rfc2047.EncodePhrase(Encoding.UTF8, subject); 3 4 var message = new MimeMessage(); 5 message.From.Add(new MailboxAddress("harq@foo")); 6 message.To.Add(new MailboxAddress("harq@bar")); 7 message.Subject = Encoding.ASCII.GetString(encoded); 8 message.Body = new TextPart("plain") { Text = @"Hello World" }; 9 10 using (var smtp = new SmtpClient()) 11 { 12 smtp.Connect("localhost", 25); 13 smtp.Send(message); 14 smtp.Disconnect(true); 15 }

smtp4dev画面
smtp4dev画面
Viewの結果

From: harq@foo Date: Sun, 04 Mar 2018 01:31:41 +0900 Subject: =?utf-8?b?5ZC+6Lyp44Gv54yr44Gn44GC44KL44CCMS4yLjMu5ZCN5YmN44Gv44G+44Gg54Sh?= =?utf-8?b?44GE44CC?= Message-Id: <NFBL3KIPS3U4.QV9M8QV27FCR3@xxxxxxxxx> To: harq@bar MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Hello World

あとは受信側のメーラー次第かなと。


上では自前のencodeを実現するために細々とやりましたが、utf-8のBASE64ならsubjectへutf-8文字列を代入するだけで、あとは上手くやってくれたはず……。

投稿2018/03/03 14:39

編集2018/03/03 23:32
HARQ

総合スコア181

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

退会済みユーザー

退会済みユーザー

2018/03/03 18:08

ご回答をありがとうございます。 いただきました助言も満足に生かせていなかった中、お見捨てになられなかっただけでも感謝しきれません。 そしてさらにサンプルコードとテストまで行っていただき、お礼の言葉もございません。 この度は本当にありがとうございました。 お陰様で、Base64につきましては安定してsubjectをエンコードすることができるようになりました。 quoted-printableに付きましては、現在は下記のようなコードを書いて試行錯誤しております。 quoted-printableの形式にすることはできたのですが、下記コードですと文字列が自動的にASCIIに変更されてしまうという欠点があります。 ひとまず、欠点解消のために、ご教授頂きましたMimeKit/Rfc2047.csをもう一度しっかりと 読んでみようと思います。 それでもどうしてもわからないようでしたら、改めて質問を掲載させていただこうと思います。 (この質問ページで質問をすると、本質問からずれてしまうようで申し訳ないので・・・) この度はご丁寧に対応くださり、誠に有難うございました。 ---- string m_subject = "吾輩は猫である。1.2.31名前はまだ無い。"; MimeKit.Encodings.QuotedPrintableEncoder ed = new MimeKit.Encodings.QuotedPrintableEncoder(); System.Text.Encoding charEcd = System.Text.Encoding.UTF8; byte[] cc = charEcd.GetBytes(m_subject); byte[] nnn = new byte[1000]; int a = ed.Encode(cc, 0, cc.Length, nnn); byte[] sn = new byte[a]; for (int i = 0; i < a;i++) { sn[i] = nnn[i]; } Mimemes.Subject = System.Text.Encoding.UTF8.GetString(sn);
HARQ

2018/03/03 23:17

MailKit/MimeKitはMimeMessageをSend時にEncodeしたと思うので、Quated-Printableの実現は(このままだと)難しいかも知れません。 SubjectにQuated-Printableの結果を入れた場合、それをBASE64したus-asciiを送信しそうな気がします(そうなってますよね?)。 何処かのclassを継承&オーバーライドすることで解決できれば良いのですが……。
guest

0

手元で確認しますとMimeKit.Encodings.Base64Encoder.Encoderが72文字毎に改行を入れているようです。そのため、本来

=?utf-8?B?5ZC+6Lyp44Gv54yr44Gn44GC44KL44CCMS4yLjMu5ZCN5YmN44Gv44G+44Gg54Sh44GE44CC?=

となるべき所が

=?utf-8?B?5ZC+6Lyp44Gv54yr44Gn44GC44KL44CCMS4yLjMu5ZCN5YmN44Gv44G+44Gg54Sh44GE44CC ?=

となってしまっています。文字数が多ければ2行目に文字が入ってきます。

対応としては改行を全て無くしてしまうのが一番簡単かも知れません。ただ、本来はMIMEのヘッダーは1行がCRLFを除き78文字以下であるべき(SHOULD)という制約があるのですが、ほとんどのメーラーは78文字以上でも表示してくれます。

なお、72文字毎に改行しているのは、本文などをBASE64エンコードしたときはそのまま貼り付けることができるからだと思われます。

投稿2018/03/03 00:36

raccy

総合スコア21735

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

退会済みユーザー

退会済みユーザー

2018/03/03 14:49

ご回答をありがとうございます。 エンコードしたバイト配列内を見てみたところ、確かに72バイト目にCR(10)が入っていることが確認できました。ありがとうございます。 早速、CRを取り除き、エンコードしたsubjectを作成したものが以下となります。 「=?utf-8?B?44GC44GE44GG44GI44GK44GL44GN44GP44GR44GT44GV44GX44GZ44Gb44Gd44Gq44Gr44Gs44Gt44Gu44Gv44Gy44G144G444G7?=」 元の文字列は「あいうえおかきくけこさしすせそなにぬねのはひふへほ」です。 ネットなどにあるツールを用いてデコードすると、元の文字列へと変換できることが確認できます。 その上でメールを送信したのですが、いざ受信したメーラーで見てみると、 subjectsがデコードされず、「=?utf-8?B?44GC44GE44GG44GI44GK44GL44GN44GP44GR44GT44GV44GX44GZ44Gb44Gd44Gq44Gr44Gs44Gt44Gu44Gv44Gy44G144G444G7?=」のままの表示となったままでした。 なぜメーラーだけデコード出来ない理由がわかりません。 何かお心当たりや、解決法を御存知でしたらこ教授ください。 何卒よろしくお願い致します。 (本文に追記として、改変したコードを掲載しておきます。 ご参考になれば幸いです)
raccy

2018/03/03 15:33

メーラーでメールのソースを見ないとこれ以上はよくわかりません。メールをファイルとして保存して、勝手にMIMEデコードしないただのテキストエディタでヘッダ部分がどうなっているかを貼り付けてください。
Zuishin

2018/03/03 15:57

それ以前にこれは quoted printable ではありませんね。
Zuishin

2018/03/03 15:58

あ、失礼しました。quoted printable をやらされてるのは私だけでした。
Zuishin

2018/03/03 16:17

メーラーだけデコードできないと言うのも事実と違います。私の回答に書いたように標準の方法でデコードできませんでした。 最後の文字が切れるような訳の分からないものになぜ固執するのか疑問です。
guest

0

何やらややこしいことをされていますが、次のソースで Base64 にエンコード・デコードできます。

C#

1using System.Text; 2 3var encoded = Convert.ToBase64String(Encoding.UTF8.GetBytes("我輩は猫である。1.2.3.名前はまだ無い。")); 4Console.WriteLine(encoded); 5var decoded = Encoding.UTF8.GetString(Convert.FromBase64String(encoded)); 6Console.WriteLine(decoded);

またメーラーの問題の可能性もありますので、別のメーラーでも確かめてください。

投稿2018/03/02 23:12

Zuishin

総合スコア28660

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Zuishin

2018/03/02 23:26

ちなみに、失敗例で表示されているものをデコードした結果が次になります。 吾輩は猫である。1.2.3?]前はまだ無い?YJ どう見てもエンコードに失敗していますね。 今回あなたの失敗は二つ。 1. 確認を怠ったこと。まずはエンコードしたものをデコードしてうまくできるかどうかの確認。また一つのメーラーだけでなく複数のメーラーを使っての確認。 2.サードパーティーのライブラリを使ったこと。標準ライブラリにある機能はしかるべき相当の理由のない限り標準のものを使いましょう。
退会済みユーザー

退会済みユーザー

2018/03/03 00:05

ご回答をありがとうございます。 追記につきまして、こちらから少し説明させていただきます。 1. お言葉を返すようで大変恐縮なのですが。 複数のメーラーでの確認、またエンコードに失敗した文字列が形成されていることについての確認は確認済みでした。その上で、ご質問させていただきました次第です。 2. こちらは私の説明不足で申し訳ございません。 なぜこのようなコードになったかと申しますと、将来的にquoted-printableや8bitなどでのエンコードを行うことをふまえての結果です。 標準ライブラリにquoted-printableへエンコードする機能が見つからなかったため、それならばBase64・quoted-printableの双方に対応したMimeKitを利用しようと思い立った次第です。 最後に、 ご回答いただきましたコードを元に以下のようなコードを作成いたしました。 string sub = "吾輩は猫である。1.2.3名前はまだ無い。"; var encoded = Convert.ToBase64String(System.Text.Encoding.UTF8.GetBytes(sub)); m_subject = string.Format("=?{0}?B?{1}?=", System.Text.Encoding.UTF8.BodyName, encoded); // ここはsubjectの形式にあるように形成しています。 誠に残念ながら、これもエンコードに失敗する例と同様の結果となってしまいました。 何か誤りがあったのならばご指摘をお願い致します。 そしてもし、さらに回答が可能なようでしたら、上記をふまえた上で 1、quoted-printableにエンコードするにはどうすれば良いのか。(また標準ライブラリにその機能があるのか) 2、エンコードに失敗する理由 をご教授いただければと思います。 何卒よろしくお願い致します。
Zuishin

2018/03/03 00:19

確認済みならば報告してください。 報告を怠ればこちらでも確認しなければならず二度手間です。 今回もそうですが、Convert を使った例で「同様の結果」ではわかりません。 どのような結果になりますか? メーラーでの画像ではこちらで打ち直さなければなりません。 テキストで質問にソースと結果を追記してください。 1.quoted-printable の変換は標準にはありません。 サードパーティーのものを使っても構いませんが、自作でも容易(十分くらいで作れる程度)です。 自作の方が手を入れやすくていいと思います。 2.こちらでは失敗しないのでまだわかりません。 どのように失敗するのか「失敗します」ではなく原因が究明できる形で報告してください。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問