配布中のライブラリについてのバグ報告・要望・質問用のスレッドです。 書き込みの際は再現用のコードやログなどもあわせて書き込んで頂けると助かります。
Smdn.Protocols.Imap4 (v20) を利用させていただき、 Gmail から、C# で、IMAP4 受信を行おうと試みています。 受信には成功したのですが、同じメールを何度も受信して しまうので、これを回避したいのですが、ドキュメントにある
request.Method = ImapWebRequestMethods.Expunge;
で試すも、うまく行きません。 IMAP URL を メールボックス形式で指定した場合には、 すべてのメールが受信できず、単一のメッセージを表すURL で 指定した場合には、すべてのメールを受信してしまいます。
プロパティをセットするタイミングが悪いのだと思いますが、 サンプルコードなどいただけないでしょうか。
あつかましいお願いで申し訳ございませんが、 よろしくお願いいたします。
>>2
具体的にどういうコードを書かれたのかわからないので推測でしか言えませんが、 もし同じUIDを指定した(=単一のメッセージを表す)IMAP URLでリクエストしたのならば、 毎回同じメールが受信されるのはIMAP的には正しい動作です。
また、メールボックス形式のURLでリクエストした場合については、メールボックスに あるすべてのメールのエンベロープだけが受信されます。 全メールの全文を 受信するわけではありません。 これはライブラリの仕様です。
EXPUNGEがうまくいかないのと、単一のメッセージを表すURLですべてのメールを 受信してしまうのはライブラリのバグかURLの形式が誤っているかどちらかだと 思うのですが、先も書いたように実際のコードまたはログがないとなんとも 言えません。
不都合のない範囲で構わないので、実際のコードまたはうまくいかなかったときの ログを見せていただけますか?
動作ログは、Smdn.Protocols.Imap4のコンパイルオプションでシンボルTRACEを 有効にした上で、アプリケーション構成ファイルに以下の内容を書けばコンソールに 表示されるようになります。
>>3 の続きです。 とりあえず動作確認もかねて書いたサンプルを提示します。
どのようなサンプルコードが必要なのかはっきりとわからなかったのですが、 POP3のような動作を期待しているように思ったので、INBOXの未読メールを 検索・ダウンロードしたあと、削除するというサンプルを書いてみました。
具体的なご指定があれば、改めて書きます。
>>4
管理人さま。 とりあえず、自己解決してました。コードは↓です。 URL 単位でリクエストした後、GetResponse() を呼んでいなかったのが原因でした。初歩的なミスですみません。
いただいたコードのおかげで、credentials の使い方もわかりましたので、拙い部分をさらに修正したいと思います。 コードのボリュームがすごかったので、追うのをあきらめ、サンプルだけでやろうとしていましたもので。
それにしても、こんなに速く、ご丁寧な回答をいただけるとは思っていませんでしたので、感激です。 本当にありがとうございました。
>>5
解決したようで何よりです。
コードを見ましたが3つほど気になった箇所があったので書いておきます。 もしすでに修正済みだったすみません。
1つめに、GetResponseで取得したWebResponseについて、Close呼ぶかusingステートメントを 使うかしたほうがいいです。 2つめも1と同様で、ImapWebResponseのCloseが呼ばれる前にWebClient.DownloadStringを 呼んでいますが、この部分はusingの外に出したほうがいいです。
この2つは、ライブラリ内部の実装の一部はCloseを呼ばないとリクエストが完結せず、 内部状態がおかしくなる場合があるためです。
3つめは、単に改善案です。 メッセージごとにEXPUNGEのリクエストを送っている部分ですが、UIDが分かっているので 1回のリクエストでまとめてEXPUNGEできます。 Gimapサーバは遅いので、メッセージの数が多い場合、メッセージの数だけEXPUNGEの リクエストを送るとだいぶ時間がかかるので、まとめて1回のリクエストにしたほうが 速く済みます。
実際のコードはこんな感じです。 テストはしてませんが、よろしければお使いください。
こんにちは。 WindowsXPでC#で、GmailをPOPで受信しようとしています。 こちらのソースとサンプルが大変充実しているようなので、使わせていただこうとしています。 たいへん貴重なものを公開してくださっていて感謝します。 さて、ところが最初から躓いていて、質問したいと思います。 (1)Smdn.Net.Pop3.Client-091\Smdn.Net.Pop3.Client\Smdn.Net.Pop3.Client.csprojをVisualC#ExpressEdition2008で開いて、まずビルドしてみました。
すると、 参照アセンブリ "Smdn.Net.Pop3.Client-0.91\build\bin\Release\Smdn.Core.Standards.dll" が見つかりませんでした。このアセンブリが別のプロジェクトによって生成された場合、このプロジェクトをビルドする前に、その生成元のプロジェクトをビルドすることを確認してください。 とエラーになりました。
(2)Smdn.Net.Pop3.Client-0.91\build\bin\Release は空だったので、Smdn.Net.Pop3.Client-091\Smdn.Net.Pop3.Client.clsを開いて、ビルドしてみました。
自動的に実装されたプロパティ 'Smdn.Net.Pop3.PopDropListing.SizeInOctets' のバッキング フィールドは、コントロールが呼び出し元に返される前に完全に割り当てられている必要があります。コンストラクタ初期化子から既定のコンストラクタを呼び出すことを検討してください。
これはどのように対処したらよいか、なにかドキュメントをご示唆いただけるとうれしいです。
(3)そもそも使用するのはどのディレクトリのどのファイル群なのでしょう? Smdn.Net.Pop3.Client-0.91\Smdn.Net.Pop3.Client\Smdn.Net.Pop3.Client 2010/04/24 23:54 15,581 PopClient.cs 2010/04/24 23:54 6,571 PopClientProfile.cs 2010/04/24 23:54 2,407 PopMessageDeletedException.cs 2010/04/24 23:54 9,659 PopMessageInfo.cs 2010/04/24 23:54 2,520 PopMessageNotFoundException.cs 2010/04/24 23:54 3,617 Trace.cs
を使うとして、 「メールボックスにあるすべてのメッセージをダウンロードしてファイルに保存する」のソースを、 main.csとして保存して、このフォルダに保存すれば使えるのでしょうか? .slnがないのでどうしたらよいかと悩んでいます。
(4)Gmailの受信サンプルで、1通のみ、またはメールボックスの全メールを受信するサンプルがありました。 このメールボックスは、GmailのIndoxにあるものを意味している、と考えてよいのでしょうか? 試せればよいのですが、まだ試せていないので、質問のみ先行します。 で、もしそうだとしたら、メールを受信したあと、IndoxからArchiveに移動したいのですが、それは可能でしょうか?
以上、初心者の質問で恐縮です。よろしくご回答いただけたらうれしいです。
Smdn.Net.Pop3.Client-0.91を利用して GmailからPop3でメール受信をしようとしています。
ドキュメント・サンプルの「Gmailアカウントのメールボックスから、最新のメッセージをダウンロードする」を例に試しているのですが、 new Uri("pops://user@pop.gmail.com /")の箇所で 「無効な URI: ホスト名を解析できませんでした」と出て失敗してしまいます。
Gmailの場合、userがxxx@gmail.comになるためUriクラスのコンストラクタに渡している文字列が 「pops://xxx@gmail.com @pop.gmail.com/」になっています。
これを回避する方法が分からないのでどうしたらいいのかご教授願えませんでしょうか。 よろしくお願いします。
すいません。 自己解決しました。 userは@以前だけでよかったようで失礼致しました。
>>7
こんにちは。 質問頂いた件について、順にお答えします。
(3)について 先ほどリリースした0.92より、実行可能なプロジェクトをソリューションに含めるようにしました。 PopClientSample.slnもしくはPopWebClientsSample.slnを開いて、Main.csを編集すれば すぐに実行できるようにしてありますので、お使いください。
(1)と(2)についても(3)で解決すると思います。
(1)について。 Smdn.Net.Pop3.Client.csprojは他のプロジェクトを参照しているので、単体ではビルドできません。 ソースパッケージにあるslnファイルを開いてビルドするか、ソースパッケージの 各ディレクトリにあるcsprojを同一のソリューションに追加してからビルドしてください。
(2)について。 0.91に含まれるPopDropListing.csは、Visual C#ではビルドエラーになるコードになっていました。 0.92で修正しましたので、そちらを使ってください。
エラーが発生した原因と対処法の解説は省きますが、以下のドキュメントがそれに関連するものになります。http://msdn.microsoft.com/ja-jp/library/bb384054.aspx 自動実装するプロパティhttp://msdn.microsoft.com/ja-jp/library/cc433530.aspx 構造体コンストラクタ
(4)について 「メールボックス」が指すのは、GmailではINBOXにあたります。 Gmailでは、POPでアクセスした場合は常にINBOXのメールを参照します。
Archiveへの移動についてですが、受信したメールはすべてINBOXとArchiveの両方に入っていたと思います。 POPでメールを受信する際、INBOXから削除してもArchiveには残ったままだと思うので、 わざわざArchiveに移動する必要はないと思います。
また、もし仮にメールボックスをまたぐ操作をしたいのであれば、POPではできないので IMAPを使う必要があります。
gmailのpop3受信非常にありがたく使わせていただきました。 まず、google appsで設定した独自ドメインでも使用可能であった事をご報告します。
appsはユーザー名がメールアドレス形式なので、サンプルであったgmailの例ではなく以下の方式で行ないました。
client = new PopClient("pop.gmail.com", 995, true, "user"); client.Connect("pass");
ここまではよかったのですが、私の場合、gmail以外にも使用するので、試しにyahooでも試したところ、どのような接続設定を行ってもう まくいきません。
client = new PopClient("pop.mail.yahoo.co.jp", 110, false, "user", "PLAIN"); client.Connect("pass");
↓以下のエラー↓
authentication failed "popgate unknown command" (result code:Error)
この指定もだめでした
client = new PopClient(new Uri(@"pop://user@pop.mail.yahoo.co.jp /")); client.Connect("pass");
↓以下のエラー↓
appropriate authentication mechanism not found
yahooは、SSLでもありませんし、特に特別な設定はしていないと思うのですが、自分の接続指定方法に誤りがあるのか、うまくいきませんでした。 ご教授頂けませんでしょうか。
まずgoogle appsでの動作報告ありがとうございます。 非常に参考になります。
yahooでの接続についてですが、以下のコードを試してみて下さい。
デフォルトでは、SSL無しの場合は平文でのログインを行わないようにしていますが、 それが原因でエラーとなっていると思います。 AllowInsecureLoginをtrueにすれば、平文でのログインを許可するようになります。
早いご回答ありがとうございました! 早速試してみたところうまくいきました。
また、yahooだけでなく、ぷららでもいきました。 ご教授ありがとうございました!
Smdn.Formats.Mime について質問です
現在メールデコードにMimeクラスを使用し、ほとんどのケースは以下でデコードし、うまく稼働しています。
しかし、一件文字化けが発生しました。bodyは次のようになりました。
試しに以下で試したところきちんとデコードされました。
何かMimeクラスの使用方法に間違いがありますでしょうか。 また、暫定的に、文字化けが発生したら、次はエンコードタイプを指定して再取得したいと考えていますが、Mimeクラスでエンコードタイプを指定する事は可能でしょうか。
お手数ですがご教授頂けると幸いです。
>>14
bodyにContent-Typeヘッダが入ってるところを見ると、読もうとしているメールの書式に異常があり、 Content-Typeヘッダ以下が本文として扱われているため、文字化けしていると思われます。 おそらくヘッダの途中(Content-Typeヘッダの前)に余計な空行があるのが原因ではないかと思いますので、 読もうとしているメールのヘッダ部分を確認してみてください。 Content-Typeヘッダが正しく読まれている場合は、m.Charsetプロパティに適切なEncodingが 設定されているはずです。
次に、エンコードタイプを指定した読み込みついては、ReadContentAsText()メソッドを呼び出す前に MimeMessage.Charsetプロパティの値を上書きすれば、その文字コードで読み込むようになっています。
なお、ヘッダでcharsetが設定されていない場合は上記のコードで対応できますが、不正なcharsetや .NET Frameworkがサポートしていないcharsetが設定されている場合は、MimeMessage.Loadが NotSupportedExceptionをスローします。 このあたりは今後のバージョンで改善するかもしれません。
バグ報告です。
MimeMessage.Load()でファイルからMimeMessageインスタンスを生成する際の LineOrientedStreamのReadLineメソッドで \r\n が内部バッファで区切られると 次のReadLineメソッドの呼び出し時に \n が1文字目に来てしまいヘッダの解析 処理がストップしてしまいます。
バグ?報告です。
EncodingUtils.GetEncoding()の引数のエンコード名の前後に 半角空白が含まれているだけで戻り値がnullになります。
「charset=iso-2022-jp 」となっているメールが読み込めないので ソースを書き換えて対応していますが、出来れば取り込んでいただきたいです。
以下、書き換えたメソッド
public static Encoding GetEncoding(string name) {
}
ご報告ありがとうございます。 LineOrientedStreamの方は次のリリースまでに修正します。 EncodingUtilsの方については、とりあえず引数の前後の空白と、アンダーバーとハイフンの違いは無視するように修正しようと思います。 クオーテーションについては>>15 の件と合わせて修正しようと思うので、どう扱うかは検討させてください。
VB.NET で使える POP クライアントを探してて、こちらに遭遇いたしました。早速軽く弄ってますが、下手な市販コンポーネントよりも構造が美しくて感激しています。(System.IO.FileInfoクラスに似たインターフェイスで~の辺)
使わせてもらってて早速で申し訳ないのですが、添付ファイルを取り出す場合には PopMessageInfo.Read ~を使って自力で取り出さないとダメなのでしょうか。 PopMessageInfo.Attachments みたいな風で添付ファイル群にアクセススできると滅茶苦茶うれしいです。
ご意見ありがとうございます。
ライブラリ設計の方針上、PopMessageInfoではメール本文の解析は行わないようにしています。 本文の解析に関わる機能を追加するとPopMessageInfoのメソッド・プロパティが多くなってしまうので、 これらの機能はSmdn.Formats.Mimeで提供するようにしています。
ですので、多少面倒ではありますが、ReadXXX等のメソッドで本文をダウンロードした後、 添付ファイルの取り出しにはSmdn.Formats.Mimeや他のライブラリを使ってください。
なお、PopMessageInfo.Attachmentsのようなメンバを追加する予定はありませんが、 今後Smdn.Formats.Mimeの方で添付ファイルに関連する機能を追加するかもしれません。
>>20 の続き。
もしPOPの代わりにIMAPが使えるのであれば、IMAPの使用をおすすめします。 IMAPなら本文の解析をサーバ側でやってくれるので、ImapMessageInfo.Save等のメソッドだけで 添付ファイルの取り出しが出来ます。 この場合Smdn.Formats.Mimeは不要です。
サンプルを書くと以下のような感じです。
先ほどSmdn.Formats.Mime version 0.21ほかをリリースしました。 修正が遅くなってしまいすみません。
version 0.21で>>16 の問題を修正しました。>>14 もしかしたら同じ原因なので、このバージョンでは正しく読み込めるかもしれません。
>>17 については、前後の空白とエンコーディング名に含まれる空白、アンダーバー、ハイフンを無視してEncodingを取得するようにしてあります。 クオーテーションについては、MimeMessageクラスを使っている限りはエンコーディング名にクオーテーションが入ることはないので、修正はしていません。 もしクオーテーションが問題となるようでしたらお知らせください。
続き。
また>>14 と>>17 の件に関連して、MimeMessage.Loadメソッドで文字セットの取得に失敗した場合に使用するエンコーディングを 指定できるオーバーロードを二つ追加しました。 使い方は次のような感じです。
上記のコードは以下のコードと等価です。
コールバックメソッドを使うようにもできます。
また何かありましたらお知らせください。
>>22
コールバック対応ありがとうございます。 理想的な対応をして頂けたので嬉しかったです。
現在数万件のメールを処理させて確認しているのですが、 以下のようなメールが来るとやはりダブルクォーテーションで Encodingの判定処理が失敗していました。
# ちなみに楽天から送られてくるメールの一部がこんな感じです。
ただ、コールバック対応のおかげで処理を続行できているので 支障ありません。
対応ありがとうございました。
以前ご質問させて頂いたgonです。 その後非常に順調に動いていたのですが、メールサーバーの入れ替えを行ったところ急に「internal error」で接続出来なくなりました。平文で以下のような接続です。
Connect部分でエラーが出ます。
ちなみに、入れ替え時のMTA側は以前と全く同じ設定で、試しにBecky!2などのメーラーで該当MTAと接続すると問題なく接続できます。 逆に、上記でyahooやぷららなどのMTAには、sslを使ってないので、同様の接続ですが接続できます。
Connect以降のどの部分でエラーかまでは追いきれていませんが何か手掛かりはありますでしょうか。又は試してみた方がいい設定など?
>>25
ありがとうございます。 はっきりとした原因が分からないので、とりあえず試せるのは以下の2点です。
まず、UseTlsIfAvailableがtrueになっているので、接続後にSSLへのアップグレードを行おうとしていて、 そこで何らかのエラーが発生し、internal errorとなっている可能性はあります。 falseにすることで状況が変わるかもしれません。
もう一つ、version 1.02でConnect()の内部実装が変わっているので、もし1.02を使っているのであれば 1.01に戻すことで接続できるかもしれません。
internal errorは予期せぬ例外の場合に起こるので、発生した例外のInnerExceptionも見てみないと エラーの原因がバグなのかサーバの問題なのか分かりません。 ですので、スタックトレースも含めて発生した例外の詳細をお教えていただけますか?
アドバイスありがとうございます 早速やってみました。 ・UseTlsIfAvailableをfalse →結果は同じでした。
・version 1.0、及びv1.01 →結果は同じでした。同様の現象が出ました。
・スタックトレース →ドキュメントを確認してapp.configに書き加え「シンボルTRACEを有効にしてビルド」をしたつもりなのですが、ログファイルが生成されるものの何も記載されない状態です。やり方が間違っている可能性が高いので、もし宜しければ設定方法を教えて頂けませんでしょうか。初心者で申し訳ございません。
ご教授ありがとうございます。スタックトレース取りました。
尚、MRAConnectorもやってみましたが、想定した設定では予期せぬエラーになってしまいました。全組み合わせでやってみましたが接続できる組み合わせはありませんでした。
先ほど問題を修正したSmdn.Net.Pop3 version 1.03をリリースしました。 頂いたスタックトレースのとおり、レスポンスの解析処理のバグが原因で例外がスローされていました。>>25 の件は今回の修正で直っていると思います。
MRAConnectorはSmdn.Net.Imap4の方と合わせて更新するつもりなので、今回はバージョンアップしません。 使う場合はSmdn.Net.Pop3を1.03に差し替えてください。
ありがとうございました! 1.03を反映してみたらうまくConnect通りました。 が、次の問題が・・・相手方のメールサーバーがUIDLに対応しているはずなのですが
で試すと非対応という判定となります。チェックをスキップして
で取ってみると取得できました。
ためしにBecky2のプロトコルログを取るとサーバーとの通信で
のようにUIDLを取得出来ている事が確認できました。
ちなみに>>32 の件も今回のMTAだけで発生しています。 coreserver.jpのメールサーバーで、MTAはqmailのようです。
>>32 -33 ServerCapabilitiesにはCAPAコマンドの結果が入りますが、サーバ側がCAPAをサポートしていない場合 (CAPAコマンドに対して-ERRとなった場合)は、ServerCapabilitiesが空になります。 そのため、仮にサーバ側がUIDLをサポートしていても、CAPAをサポートしていなければ ServerCapabilities.Contains(PopCapability.Uidl)はfalseを返します。
なので、ServerCapabilities.Contains(PopCapability.Uidl)が
trueの場合は、確実に UIDLをサポートしている
falseの場合は、もしかしたら UIDLをサポートしているかもしれない
と判断したほうがいいです。
お使いのqmailでは単にCAPAをサポートしていないだけと思われるので、UIDLをサポートしていることが 明らかなのであれば、チェックをスキップしてしまっても構わないと思います。
>>34 続き ちなみに、CAPAをサポートしていないサーバに対してUIDLをサポートしていないこと を 確実に判断するには、実際にコマンドを送信してみないとわかりません。
次のようにすれば、UIDLをサポートしているかどうかを確実に判断できると思います。
現在のPopMessageInfo.UniqueIdが例外をスローする実装は使いにくそうなので、 今後のバージョンではunique-idを取得できなかった場合はnullを返すように 変更するかもしれません。
また、上記のとおりサンプルコードのところで記載しているやり方はあまり確実ではないので、 これも近々書き直します。
ご説明ありがとうございます!今回はスキップして処理しました。 返答が丁寧で且つ早いので非常に感謝しています。
お騒がせしました。
素晴らしいサイトの運営、敬服いたします。 imaps でgmail の受信は順調に作動しています。 とても感謝しています。 popで、ロリポップや、IIS のメールの受信を試みています。
ロリポップで、 var client = new PopClient("pop3.lolipop.jp", 110, false, "user"); もしくは、 var client = new PopClient(new Uri(@"pop://userd@pop3.lolipop.jp /")); client.Profile.AllowInsecureLogin = true; client.Connect("pass");
で実験しているのですが、 以下のようなエラーが出てしまいます。
ファイルまたはアセンブリ 'Smdn, Version=0.40.0.0, Culture=neutral, PublicKeyToken=null'、 またはその依存関係の 1 つが読み込めませんでした。指定されたファイルが見つかりません。
勉強不足のは重々承知していますが、時間がないため、指定の誤りをご指摘いただけたら幸いです。 よろしくお願いします。
ありがとうございます。 動作報告も非常に助かります。
件のエラーについてですが、プロジェクトの参照にSmdn-netfxX.Y.csprojを追加するか、 実行ファイルと同じ場所にSmdn.dllを置くことで解決すると思います。 プロジェクトの参照設定をご確認ください。
お忙しい中、御指示いただきまして、感謝しております。 Smdn.dll Smdn.Core.Standards.dll の二つを参照設定して置くのを忘れていました。 恥ずかしいかぎりです。 ロリポップも、IISも、無事作動いたしました。 ありがとうございました。 これからも、ご活躍を祈っております。
有用なライブラリをありがとうございます。 Smdn.Net.Pop3.Clientについて、CoreServerに登録してある独自ドメインのメールを使用したいのですが、力量不足で接続できません。 アドバイスをいただけると幸いです。
現状では http://www.coreserver.jp/help/index.php/sharedssl/ を参考にして、
var client = new PopClient("s00-coreserver-jp.value-domain.com", 995, true, "user@domain"); client.Connect("pass");
として試しているのですが、connect failedになってしまいます。 サーバのメール設定ではPOPのアクセスは許可してあります。
知識不足ゆえの手詰まりで恥ずかしいのですが、ご指摘いただければ幸いです。
上記の件について、自己解決いたしました。 CoreServerでも使用できたことを報告いたします。 お騒がせしたことをお詫び申し上げます。
ソースコードは変更せず、プロキシ設定周りを変更したところ受信することができました。 基本的な部分について確認を怠っていてお恥ずかしい限りです。
補足。 プロキシを使用しないネットワークでは受信できましたが、プロキシ使用環境下でこのライブラリを使用することは可能ですか? IEプロキシですべてのプロトコルに使用する設定にしても接続できませんでした。
お手数ですがアドバイスいただけると助かります。
ありがとうございます。
プロキシを通した接続については、現時点では考慮していません。 ただ、テストはしていませんがプロキシを通したとしても動作するのではないかと思います。
connect failedになったのは、プロキシを通さず直接サーバに接続しようとしたからではないでしょうか? プロキシを通すなら、コンストラクタに渡すホスト名とポート番号を、
のようにプロキシサーバのものに変えれば接続できるかもしれません。 それ以上はスローされた例外の詳細と動作ログを見てみないと原因は分かりません。
IEでのプロキシ設定についてですが、Smdn.Net.Pop3.Clientの動作には影響しないのではないかと思います。 この点についてはこちらでも調べてみます。
お忙しい中返答いただきありがとうございました。 コンストラクタにプロキシのホスト名とポート番号を渡してみましたが、この場合はPOPのホスト名とポートを指定することはできない…ですよね。 教えていただいた方法では実現することができませんでした。
学内プロキシを越えてCoreServerにPOPでアクセスできれば理想なのですが…もう少し悩んでみます。
なるほど、IEのプロキシは影響しないのですね。 お手数をおかけしますが、もし有効な手段がありましたらご教示お願いいたします。 どうもありがとうございました。
一度、お恥ずかしい質問で、ご迷惑をおかけした者です。 とても素晴らしいお仕事に、ただただ頭が下がる思いです。 その後のご報告です。 IMAP POP3 で、 ロリポップ、HETEML, Gmail, YahooMail, IIS など、順調に動作しています。 ありがとうございます。 今後とも、よろしくお願いします。
問題なく動作しているようで何よりです。 動作報告もありがとうございます。
不具合報告です。
MimeMessage.Load(string, EncodingSelectionCallback)メソッドが指定したコールバック関数を使ってくれません。
ソースを確認したところ MimeMessage.Load(Stream) メソッドが呼ばれていました。
報告まで。
ご報告ありがとうございます。
修正はコミットしたので次のバージョンでは修正されますがリリースがだいぶ先になりそうなので、 お手数をお掛けしてすみませんが、リリースまでは最新版をチェックアウトするかソースの以下の箇所を直接修正してください。
対応有難う御座います。 とりあえず直接Load(Stream, EncodingSelectionCallback)メソッドを呼び出すように変更して対応しました。
Smdn.Formats.Mime ライブラリを利用させて頂いております。
Smdn.Formats.Mime-0.22 において EncodingSelectionCallback を利用してエンコーディングの フォールバックを行っているのですが、ヘッダにおいてフォールバックが呼び出されない現象が 発生しています。
MimeMessage.Load ではコンテントのエンコーディングが解釈できない場合に EncodingSelectionCallback を利用する様になっているのですが、Decode配下のヘッダ解釈に selectFallbackCharset が受け渡されて いない様に見えます。
以下の修正にてヘッダでの B/Q エンコーディングのcharsetの解釈に selectFallbackCharset が利用され る様になるのですが、よろしければ反映頂けないでしょうか。
(iPod のメーラーがSubjectにcp932のquated printableを投げてくるという酷い実装で びっくりしましたです。)
>>52
ご要望・ご提案ありがとうございます。 早速ですが反映したバージョンSmdn.Formats.Mime 0.23をリリースいたしました。 もともとselectFallbackCharsetはContent-Typeの解釈(ボディ部のデコード用)のみに使用するものでしたが、 このバージョンでは、>>23 と同じコードでB/Qエンコードされたヘッダのデコード時にもselectFallbackCharsetを呼び出すようにしました。 書き込んでいただいた内容をほとんどそのまま使用させて頂きました。 ありがとうございました。
なお、本バージョンには>>50 の修正も含めて有ります。
また、本バージョンではMimeEncoding.Decodeメソッドで文字コードが見つからない場合にスローされる例外が FormatExceptionからEncodingNotSupportedExceptionに変更になりましたので、直接使用されている場合はご注意ください。
>>53
素早い対応ありがとうございます。 修正リリースに反映されている事を確認させて頂きました。
こんにちは。初めまして。 未だに basp を使ってまして、そろそろネイティブ化したいなというところで貴ライブラリを発見致しました。
で早速の質問で恐縮ですが、new Smdn.Net.Pop3.Client.PopClient で uri を引き渡すかと思いますが、UserName もしくは Password の中に「@」が含まれている場合、System.UriBuilder がエラーになってしまい、Smdn.Net.Pop3.Client.PopClient に引き渡せません。
対象の POP3 アカウントが「xxx@yyy.com 」の「xxx」のみでなく、フルに書かないといけない場合とか。 「@」を含まない場合は正常に動作するのですが、何か回避策はあるのでしょうか。
>>55
こんにちは。 ご報告ありがとうございます。
現時点ではUserNameもしくはPasswordに「@」を含むURLをPopClientに渡すと例外エラーとなります。 この不具合については修正しますので、すみませんが次のリリースまでお待ちください。
なお、UriBuilderでは次のようにパーセントエンコードすれば「@」を含む文字列を設定することができます。
もうひとつ念のために書き添えておくと、PopClientはURLにパスワードが含まれていてもパスワードとしては使用しません。 PopClient.Connectメソッドの引数で渡された文字列のみをパスワードとして扱います。 PopClient.Connectメソッドの方は、パスワードに「@」が含まれていてもパーセントエンコード等のエスケープを行う必要はありません。
>>55
先ほどUserNameに「@」を含むURLを設定できない不具合を修正した Smdn.Net.Pop3 version 1.14をリリースしました。
これで問題なく動作するようになりますので、どうぞご利用ください。
>>58
こんにちは。 ご利用頂きましてありがとうございます。
OAuth認証を行う件についてですが、まず当方はOAuthについての知識があまりありませんので、 以下不十分な回答となるかもしれない点ご容赦ください。
早速ですが、現状Smdn.Net.Imap4.Clientが使用しているSASLの実装Smdn.Security.Authentication.Saslには OAuth認証の実装は含まれていないので、まずSASLメカニズムに沿ってOAuth認証を行うクラスを作成します。
https://developers.google.com/gmail/xoauth2_protocol を読む限りでは、次のような実装でよさそうです。
Smdn.Net.Imap4.Clientは、IMAP AUTHENTICATEコマンドを送出する際にExchangeメソッドを呼び出し、 clientResponseに設定された内容をBase64でエンコードした上でサーバー側に送出します。
あとは、ImapClient.Connectメソッドを呼び出す際の引数に、上記のXOAuth2Mechanismのインスタンスを渡します。 これにより、IMAP AUTHENTICATEコマンドを送出する際にこのクラスが使われるようになります。
これで https://developers.google.com/gmail/xoauth2_protocol で示されているような動作となるはずです。
なお既存のSASL関連の実装はSmdn.Security.Authentication.Sasl/Smdn.Security.Authentication.Sasl.Clientフォルダにある各クラス、 AUTHENTICATEコマンドの処理はSmdn.Net.Imap4.Client/Smdn.Net.Imap4.Client.Transaction.BuiltIn/AuthenticateTransaction.csに 含まれています。 認証時の動作をトレースする場合はこれらのファイルをご覧ください。
おお・・・ 早速ありがとうございます。 試してみて結果をご報告差し上げます!
早速試してみました。
XOAuth2Mechanismを渡した後のclient.Connect の後で exception が発生しました。 エラーメッセージは、"internal error"
下記のログを元にデバッグポイントを貼った所、下記の exchange already succeeded の exception が発生しているようでした。何かアドバイス頂けますでしょうか?必要であればこちらから可能な限り情報はお出しします。
ここからログ
最終的にうまくいきました。
こちらのいらない修正
access token の期限切れ
など、こちらがわのミスによるものだったようです。 頂いたコードで動きました。
以下、ImapConnection.cs の SetCommand(), TryReceiveResponse() から引き抜いた Authentication の一連の流れです。 ご参考までに。
{Condition=Ok, ResponseText={Code=, Arguments=[], Text=Gimap ready for requests from 121.102.95.209 c2if1415404pbm.166}} {CommandString=CAPABILITY, Tag=0000, Arguments=} {Type=CAPABILITY, Data={Text:IMAP4rev1}, {Text:UNSELECT}, {Text:IDLE}, {Text:NAMESPACE}, {Text:QUOTA}, {Text:ID}, {Text:XLIST}, {Text:CHILDREN}, {Text:X-GM-EXT-1}, {Text:XYZZY}, {Text:SASL-IR}, {Text:AUTH=XOAUTH}, {Text:AUTH=XOAUTH2}} {Tag=0000, Condition=Ok, ResponseText={Code=, Arguments=[], Text=Thats all she wrote! c2if1415404pbm.166}} {CommandString=AUTHENTICATE, Tag=0001, Arguments=XOAUTH2, {access_token}} {Type=CAPABILITY, Data={Text:IMAP4rev1}, {Text:UNSELECT}, {Text:IDLE}, {Text:NAMESPACE}, {Text:QUOTA}, {Text:ID}, {Text:XLIST}, {Text:CHILDREN}, {Text:X-GM-EXT-1}, {Text:UIDPLUS}, {Text:COMPRESS=DEFLATE}, {Text:ENABLE}, {Text:MOVE}, {Text:CONDSTORE}, {Text:ESEARCH}} {Tag=0001, Condition=Ok, ResponseText={Code=, Arguments=[], Text={userid} {username} authenticated (Success)}} {CommandString=NAMESPACE, Tag=0002, Arguments=} {Type=NAMESPACE, Data={List:{List:{Text:}, {Text:/}}}, {NIL}, {NIL}} {Tag=0002, Condition=Ok, ResponseText={Code=, Arguments=[], Text=Success}} {CommandString=ID, Tag=0003, Arguments=NIL} {Type=ID, Data={List:{Text:name}, {Text:GImap}, {Text:vendor}, {Text:Google, Inc.}, {Text:support-url}, {Text:http://support.google.com/mail }, {Text:version}, {Text:gmail_imap_130623.00_p0}, {Text:remote-host}, {Text:121.102.95.209}}} {Tag=0003, Condition=Ok, ResponseText={Code=, Arguments=[], Text=Success}}
>>61 >>62
結果をご報告頂きありがとうございます。 動作結果を見る限り問題なく認証に成功しているようでなによりです。
以下は参考情報です。
internal errorが発生した理由は、XOAuth2Mechanismが、認証に失敗した際に返されるエラーメッセージを 予期しないレスポンスとして扱うようになっていたことが原因です。
XOAuth2Mechanismを次のように作り変えることにより、OAuth認証に失敗した場合には通常の認証失敗時と同様に ImapAuthenticationExceptionをスローするようにできます。 また、必要に応じてserverChallengeを見ることにより、 Gmailサーバーが返送してくるJSON形式のエラーメッセージを読むことができます。
(最初からこのような実装にしておけば問題点の発見が容易だったと思います。 お手間を取らせてしまいすみません。)
さらなる改良コードありがとうございます。 早速試してみます。 Gmailのaccess tokenは通常1時間程度で期限が切れてしまい、認証に失敗した場合、取り直しが必要になるようなので、エラーメッセージが出るのはとても助かります!
今後のバージョンでXOAuth2Mechanismをライブラリに組み込み、ユーザー側では必要なパラメータを指定して インスタンスを作成するだけで済むようにしたいと考えています。
今のところ以下のような使い方ができるようにしようと考えていますが、もしよろしければ どのような使い方をしたいか、実際に使用する上で不便な点などありましたらご意見をいただけると幸いです。
お返事遅れました。
頂いたコード試してみました。
Authentication Command に対して、 {CommandString=AUTHENTICATE, Tag=0001, Arguments=XOAUTH2, {Credential}}
下記のレスポンス、 {"status":"400","schemes":"Bearer","scope":"https://mail.google.com/ "}
以下、トレースログ
{CommandString=, Tag=, Arguments=*} {CommandString=, Tag=, Arguments=*} {Tag=0001, Condition=No, ResponseText={Code=ALERT, Arguments=[], Text=Invalid credentials (Failure)}} {Tag=0001, Condition=No, ResponseText={Code=ALERT, Arguments=[], Text=Invalid credentials (Failure)}} 'Smdn.Net.Imap4.ImapAuthenticationException' の初回例外が Smdn.Net.Imap4.Client.DLL で発生しました。 'Smdn.Net.Imap4.ImapAuthenticationException' の初回例外が Smdn.Net.Imap4.Client.DLL で発生しました。
となり Invalid credential である所まで特定できるようになりました。
このライブラリにOAuth2が対応されるのは素晴らしいと思います。 GmailのOauth2であれば、expires_in をチェックして期限が切れていれば、access_tokenの取り直しといったフローがよさそうです。 (下記がaccess_token取得時に得られるパラメータ一覧です。)
{
}
従いまして、コンストラクタには、DateTimeの expires_in も入っているとなお取り回しがよさそうです。 (オプショナル扱いでもよいかもしれませんが・・・) Gmailのexpires_inは、秒単位で来ますので、取得時に現在時刻に足して保存しておくと言った形で私は実装しました。
初めまして。ライブラリー使わせて頂いているものです。 タイムアウトの動作について質問させてください タイムアウトの設定(*)を300秒にしているのですが、なぜか21秒ぐらいでタイムアウト例外が発生してしまいます。タイムアウトの発生方法はケーブル切断によるものです。 (*)以下のプロパティを全て300秒に設定 Client.Profile.Timeout Client.Profile.SendTimeout Client.Profile.ReceiveTimeout
なお、20秒以下の設定は正しく反映されて動作します。例えば5秒に設定すれば、5秒でタイムアウト例外が発生します。 なぜ、300秒に到達せずタイムアウト例外が発生するのでしょうか?上記のプロパティ以外にタイムアウトの動作に影響を与えるようなプロパティがある等、考えられる理由があれば教えてもらえないでしょうか?
>>68
ご利用頂きましてありがとうございます。
ケーブル切断でタイムアウト設定値に到達する前に例外となる原因についてははっきりしません。 スローされたTimeoutExceptionのMessageプロパティやInnerExceptionプロパティ、例外が発生した際のスタックトレースが あれば何か状況がわかるかもしれません。 もしくはSocketクラスがそのような動作となっているのかもしれません。
タイムアウトのプロパティについてですが、Client.Profile.Send/ReceiveTimeoutに設定された値は 接続時にのみ使用され、以降のコマンド送受信時にはClient.Send/ReceiveTimeoutプロパティに設定された値を使用します。 (Client.Send/ReceiveTimeoutへの値の設定は常にClient.Profile.Send/ReceiveTimeoutに反映されます)
Client.Send/ReceiveTimeoutに設定した値は、そのままSystem.Net.Sockets.SocketクラスのSend/ReceiveTimeoutプロパティに設定されます。 そのため、SocketクラスがSend/ReceiveTimeoutの設定値未満でSocketError.TimedOutの例外をスローするような ことがあれば、そのような事象が起こりえます。
Client.Timeoutは、コマンドの送信とレスポンスの受信を行うメソッドを非同期で呼び出した際の終了待ちに使用しています。 そのためClient.TimeoutにClient.SendTimeoutより小さい値を指定すれば、送信でのタイムアウトが起きる前に TimeoutExceptionをスローする場合があります。
これ以外にはタイムアウト動作に影響するプロパティはありません。 引き続きこちらでも調べてみますが、ケーブル切断を行える環境をすぐに用意できないので調査に時間がかかりそうです。
68のものです。 スタックトレース取得しました。(なお、以下のトレースはケーブル切断によって発生した例外ではなく、誤ったアドレス(POP3サーバではないマシン)に対してPOP3アクセスした場合のトレースです。こちらも同様に21秒ぐらいでタイムアウトが発生します。)
ここから -- [Smdn.Net.Pop3.Protocol.PopConnectionException] {"connect failed"}
StackTrace: 場所 Smdn.Net.ConnectionBase.Connect(String host, Int32 port, Int32 millisecondsTimeout, UpgradeConnectionStreamCallback createAuthenticatedStreamCallback) 場所 Smdn.Net.Pop3.Protocol.Client.PopConnection..ctor(String host, Int32 port, Int32 millisecondsTimeout, UpgradeConnectionStreamCallback createAuthenticatedStreamCallback) 場所 Smdn.Net.Pop3.Client.Session.PopSession.Connect(String host, Int32 port, Int32 connectTimeout, Int32 sendTimeout, Int32 receiveTimeout, UpgradeConnectionStreamCallback createAuthenticatedStreamCallback) 場所 Smdn.Net.Pop3.Client.Session.PopSession..ctor(String host, Int32 port, Int32 transactionTimeout, Int32 sendTimeout, Int32 receiveTimeout, UpgradeConnectionStreamCallback createAuthenticatedStreamCallback) 場所 Smdn.Net.Pop3.Client.Session.PopSessionCreator.CreateSession(IPopSessionProfile profile, SaslClientMechanism authMechanismSpecified, UpgradeConnectionStreamCallback createSslStreamCallback, PopSession& session) 場所 Smdn.Net.Pop3.Client.Session.PopSessionCreator.CreateSession(IPopSessionProfile profile, SaslClientMechanism authMechanismSpecified, UpgradeConnectionStreamCallback createSslStreamCallback) 場所 Smdn.Net.Pop3.Client.PopClient.ConnectCore(ConnectParams params) 場所 Smdn.Net.Pop3.Client.PopClient.Connect(String password) 場所 jp.co.XXX.CheckMailThrd.ReceiveAndAdmit(MailAutoAdmitTask task, Boolean SendConnFailedMail) 場所 D:\\Work\\Develop\\src\\CheckMailThrd.cs:行 319"
InnerException {"接続済みの呼び出し先が一定の時間を過ぎても正しく応答しなかったため、接続できませんでした。または接続済みのホストが応答しなかったため、確立された接続は失敗しました。 192.168.168.182:110"} System.Exception {System.Net.Sockets.SocketException}
InnerException StackTrace: Server stack trace: 場所 System.Net.Sockets.Socket.Connect(IPAddress[] addresses, Int32 port) 場所 System.Net.Sockets.Socket.Connect(String host, Int32 port) 場所 System.Runtime.Remoting.Messaging.StackBuilderSink._PrivateProcessMessage(IntPtr md, Object[] args, Object server, Int32 methodPtr, Boolean fExecuteInContext, Object[]& outArgs) 場所 System.Runtime.Remoting.Messaging.StackBuilderSink.AsyncProcessMessage(IMessage msg, IMessageSink replySink)
Exception rethrown at [0]: 場所 System.Runtime.Remoting.Proxies.RealProxy.EndInvokeHelper(Message reqMsg, Boolean bProxyCase) 場所 System.Runtime.Remoting.Proxies.RemotingProxy.Invoke(Object NotUsed, MessageData& msgData) 場所 System.Action`2.EndInvoke(IAsyncResult result) 場所 Smdn.Net.ConnectionBase.Connector.Connect(String host, Int32 port, Int32 millisecondsTimeout) 場所 Smdn.Net.ConnectionBase.Connect(String host, Int32 port, Int32 millisecondsTimeout, UpgradeConnectionStreamCallback createAuthenticatedStreamCallback)"
場所 Smdn.Net.Pop3.Client.Session.PopSession.PostProcessTransaction(IPopTransaction t)\r\n 場所 Smdn.Net.Pop3.Client.Session.PopSession.EndProcessTransaction(IAsyncResult asyncResult)\r\n 場所 Smdn.Net.Pop3.Client.Session.PopSession.ProcessTransaction(IPopTransaction t)\r\n 場所 Smdn.Net.Pop3.Client.Session.PopSession.Connect(String host, Int32 port, Int32 connectTimeout, Int32 sendTimeout, Int32 receiveTimeout, UpgradeConnectionStreamCallback createAuthenticatedStreamCallback)\r\n 場所 Smdn.Net.Pop3.Client.Session.PopSession..ctor(String host, Int32 port, Int32 transactionTimeout, Int32 sendTimeout, Int32 receiveTimeout, UpgradeConnectionStreamCallback createAuthenticatedStreamCallback)\r\n 場所 Smdn.Net.Pop3.Client.Session.PopSessionCreator.CreateSession(IPopSessionProfile profile, SaslClientMechanism authMechanismSpecified, UpgradeConnectionStreamCallback createSslStreamCallback, PopSession& session)\r\n 場所 Smdn.Net.Pop3.Client.Session.PopSessionCreator.CreateSession(IPopSessionProfile profile, SaslClientMechanism authMechanismSpecified, UpgradeConnectionStreamCallback createSslStreamCallback)\r\n 場所 Smdn.Net.Pop3.Client.PopClient.ConnectCore(ConnectParams params)\r\n 場所 Smdn.Net.Pop3.Client.PopClient.Connect(String password)\r\n 場所 jp.co.XXX.CheckMailThrd.ReceiveAndAdmit(MailAutoAdmitTask task, Boolean SendConnFailedMail) 場所 D:\\Work\\Develop\\src\\CheckMailThrd.cs:行 322"
なお、上記のソースをデバッガで確認したところ、例外が発生したときのClient.Send/ReceiveTimeout、Client.Profile.Send/ReceiveTimeoutは全て300秒になっていました。
上記の情報で原因を特定できないでしょうか?
68のものです。
申し訳ありません。自己解決しました。タイムアウトの概念を誤解していました。 Send/ReceiveTimeoutはTCPコネクションが確立されてから用いられるものなので、110ポートが空いていないサーバーへのPOP3アクセスが300秒経過せず切断されるのは当然ですね。 試しに110ポートをListenするだけのテストプログラムを作成し、テストプログラムが動作するサーバに対して監視したところ、正しく300秒でタイムアウトが発生しました。
お手数をおかけして申し訳ありませんでした。
>>70
>>71
スタックトレースありがとうございした。 また、すでに解決したようで何よりです。
質問を頂いた時点で「タイムアウト時間を満了する前にTimeoutExceptionが スローされた」と勘違いしていました。 そのため当を得ない回答となってしまったようです。 すみません。
以下蛇足ではありますが、21秒でTimeoutException以外 の例外で接続に失敗する動作について調べた結果と、 接続時に300秒まで待ち合わせる方法について書き記しておきます。
Socket.Connectメソッドは、接続先が応答しない場合などでは最大21秒でSocketExceptionをスローするという 動作となっています。 一方、Socket.Connectメソッド自体にはタイムアウト時間を指定する引数がないので、21秒でSocketExceptionを スローするという動作は変更することができません。
このため、ライブラリは接続開始から21秒後に発生したSocketExceptionをInnerExceptionに格納し、 PopConnectionExceptionをスローします(頂いたスタックトレースにあるとおりの動作)。
上記のようなSockect.Connectメソッドの動作により、本ライブラリでは、
Timeoutプロパティの設定値を満了した場合はTimeoutException
(Timeoutプロパティの設定値に関わらず)21秒が経過した場合はPopConnectionException
をスローするのが接続先無応答時の動作ということになります。
接続時に最大21秒でタイムアウトという動作を変更したい場合はレジストリの値(TcpMaxConnectRetransmissions)を 変更する必要があるようです。
従って、接続時に300秒まで待ち合わせるようにしたいのであれば、上記のレジストリの値を変更する必要があります。
補足です。
ConnectメソッドはSendTimeout/ReceiveTimeoutプロパティの値を参照しません。 Timeoutプロパティに設定されている値でタイムアウトします。
68のものです。
なぜ21秒でコネクションタイムアウトが発生するか理由が分からず、もやもやしていましたが、レジストリの値によって時間が決まっていることが分かり、疑問が解消しました。 丁寧な解説ありがとうございました。
初歩的な質問となるのですが、POP3.Client(1.15.0.0)を利用させて頂いております。
自社のPOPサーバより取得するバッチを作ろうとしていて、一点御伺いさせて下さい。
MarkAsDeleted()メソッドでIsMarkedAsDeleted=trueに一旦なるのですが、 その後再取得させた際にはIsMarkedAsDeleted=falseとなります。
これは何に由来するなどはお分かりになりますでしょうか。
コードはこの様な記述です。
>>75
ご利用頂きましてありがとうございます。
MarkAsDeleted()メソッドによって付けられる削除マークは、永続的に保持されるフラグではなく、 ログインしている間のみ保持されるフラグです。 そのため、MarkAsDeleted()メソッドで削除マークを付けた場合でも、実際に削除を行わないまま 切断すればフラグの状態は元に戻り、次回ログイン時に再取得すると削除マークが付けられていない状態、 つまりIsMarkedAsDeleted=falseとなります。
また、削除マークを付けたメッセージは、QUITコマンドを発行しない限り実際には削除されません。
Disconnect()メソッドでは、QUITコマンドを発行せずに切断 します。 そのため、 削除マークが付けられているメッセージは削除されずサーバーに残ったままとなり、 次回ログイン時にも再取得されることとなります。
これが「再取得するとIsMarkedAsDeleted=falseとなる理由」になります。
一方、Logout()メソッドを使えば、QUITコマンドを発行した後に切断 します。 この場合、削除マークを付けられているメッセージは切断前にサーバー上から削除され、 次回ログイン時には再取得されなくなります。
従って、コード中で呼び出しているDisconnect()メソッドをLogout()メソッドに書き換えれば、 「サーバー上のすべてのメッセージを取得・保存したのち、サーバー上から削除する」という動作にする ことができます。
Smdn.Net.Imap4.Clientライブラリを利用させていただき、IMAPメーラーを作成しておりますが、 以下の事象が発生しており開発が難航しております。 対処法等、ございましたらご教授いただけますと幸いです。
【発生事象】 SMDNライブラリを使用して社内のIMAPサーバへアクセスした際、 StartIdle()でIDLE開始でCPUが高負荷状態となる。 この時以下のエラーが出力され続けます。
【エラー内容】
【環境】 OS:Windows7/8 開発環境:VS2012 .NET 3.5 ※ .NET 4.5 と .NET 3.5 をインストール済み WPFアプリケーションにて作成
<参照ライブラリ/バージョン> Smdn.Core.Standards.dll 0.40.0.0 Smdn.dll 0.40.0.0 Smdn.Net.Imap4.Client.dll 0.90.0.0(一部改変あり。下記【備考】参照) Smdn.Net.Imap4.dll 0.90.0.0 Smdn.Net.MessageAccessProtocols.dll 0.90.0.0 Smdn.Security.Authentication.Sasl.dll 0.33.0.0
【テストアプリ実装機能】 ①待機開始ボタン押下することでStartIdle()を呼び出しIDLE開始 ②RecentMessageCountChangedイベントを補足してメッセージ表示
【発生事象】 ①テストアプリを実行して「待機開始」ボタンを押下し、IMAP IDLEを開始すると一定時間後(2分以内)にCPUが高負荷状態となる
【テストアプリ(コードビハインド)】
【備考】 社内サーバーと通信ができないためライブラリを改修 ImapResponseReceiver.cs、67行目から抜粋 修正個所は // add startと // add end で囲っています。
>>77
ご利用頂きましてありがとうございます。
こちらではStartIdle()で高負荷状態になる状況は再現できなかったのですが、 SSL接続中にIDLEを行った場合に意図していないデータを受信する問題が見つかりました。 高負荷状態になる問題はこれに関連するものと思われます。
この問題の調査と修正には時間が掛かりそうなので、ご不便をお掛けしますが 以下どちらかの方法をとりあえずの対処として頂ければと思います。
(セキュリティ上問題なければ)SSLを使わずにサーバーへ接続する
StartIdle()/IDLEコマンドは使わず、以下のようにImapOpenedMailboxInfo.Refresh()メソッド/NOOPコマンドを使用して新着メールをチェックする
また、調査の参考として、以下の情報について差し支えない範囲で構いませんのでご提供いただけると助かります。
お使いのIMAPサーバーの種類
ImapResponseReceiver.csに修正が必要となった理由 (あるいは、IDLE中にどのようなレスポンスが返送されてきたか)
高負荷状態になった際の動作ログと送受信内容 (http://smdn.jp/works/libs/Smdn.Net.Imap4.Client/docs/#logging )
なお、IOExceptionとSocketExceptionについてですが、IDLE中にサーバーからのレスポンスが無い場合には 数十秒に一度程度発生します。 このエラーが出ていることに関しては(現時点では)意図した通りの動作です。
>>77
調査したところ、現在こちらで把握している問題は以下の修正 (IDLE中のConnection.ReceiveTimeoutをTimeout.Infiniteにする) を施すことにより対処できることがわかりました。
高負荷状態になる問題もおそらくこの修正で解決すると思われます。 恐れ入りますが以下の修正を施した上で再度アプリのテストをしていただければと思います。
こちらでも引き続き検証を続けますが、この対処で問題なさそうなら この修正を含めたバージョンをリリースしようと思います。
77のものです。 早々のご調査大変ありがとうございます。 79の修正については現在確認中です。追ってご連絡をさせていただきます。 77でご質問いただきました参考情報につきましては、 2.ImapResponseReceiver.csに修正が必要となった理由 (あるいは、IDLE中にどのようなレスポンスが返送されてきたか) のみの回答となります。申し訳ありません。 IDLEコマンド発行後のレスポンスが"+"のみで後に文字列が続かないため修正が必要となりました。
>>77 のものです。>>78 でお問い合わせいただいた 3.高負荷状態になった際の動作ログと送受信内容 のログが取得できました。 以下に掲載します。(掲示板の最大文字数に引っかかるため繰り返されるエラー部分は(中略)としています。) 管理人様で把握されている問題とログの内容が一致しているかご確認いただけないでしょうか?
>>81
回答が遅くなりましたが、動作ログのご提供ありがとうございました。
動作ログのみで実際の送受信内容が含まれていないのではっきりしない点は多いですが、 ログ内容から推測した結果としては、>>79 の対処を行えばおそらく動作する、 あるいは好転するのではないか、という感触です。
ですので、こちらとしては>>79 のテスト結果を待ちたいと思います。
以下は調査した結果と不明な点の整理です。
現在までで分かっているのは、「SSL接続でのIDLE時、タイムアウトする度にサーバーから 送信されるはずのない文字を含む文字列を読み取ってしまう」ということです。 これにより、IDLEが正しく動作しなくなっていました。
そこで、Timeout.Infiniteを設定してタイムアウトさせないようにしたところ、 非SSL接続時と同様問題なく動作するようになりました。 (そもそも、このタイムアウトの設定自体が不要なものでした。 また、 なぜSSL接続時のみ発生するかという点についてははっきりしません。)
>>80 の"+"のみが返される問題はおそらくこれが原因(既に読み込んだ内容を 再度読み取っている?)と思われるので、>>79 の修正を適用すれば不要に なるのではないかと思います。
一方、こちらの環境では、タイムアウト間隔として設定していた30秒毎に 例外エラーが発生していたのに対し、そちらの環境では>>81 の動作ログにあるとおり 一度タイムアウトすると30秒より短い間隔で継続的に発生するという、 その違いについては理由がわかりません。
サーバーの実装によるものか、これまで分かっている以外の問題によるものか はっきりしないため、この点でもやはり>>79 の修正でどう変わるかを 見させていただきたいと思います。
管理人様>>77 のものです。 ご調査大変ありがとうございます。 回答が遅くなり、申し訳ありません。>>79 の修正で問題は発生しなくなっております。
管理人様
現在使っているアプリでBSMTP.DLLからSmdn.Net.Pop3.Clientへの乗り換えを検討しています。 受信するメールはgoogle appでのgmailで 単純な受信は>>11 の方と同じように成功したのですが、 gmailに実装されているrecentモード( http://gmail.1o4.jp/recent.html ) で以下のように接続しようとすると接続エラーが発生します。
ソース
エラー
おそらく「:」によりユーザ名が内部で正しく取得できてないと思われるのですが どうにか回避できる手段はございませんでしょうか。
それではよろしくお願いします。
>>86
ご利用頂きましてありがとうございます。 ご指摘頂いたとおり、現在のバージョンではユーザー名に":"を含めることができません。
ソースコードを編集して以下の修正を施すことによりユーザー名に":"を含めることが できるようになります。 (PopUriBuilder.csでencUserの"@"を"%40"に置き換えている次の行に、 ":"を"%3A"に置き換える処理を加える)
recentモードが使えるよう、今後のバージョンでユーザー名に":"を含められるように しようと思いますが、少々検討が必要なのでリリースまでにはお時間を頂くと思います。
お手数をお掛けしますが、ソースコードを直接修正することで回避していただければと思います。
管理人様
>>86 の者です。 返事が遅れましたが、 修正後ビルドし無事受信することを確認しました。 ご返答有難うございました。
>>89
ご利用いただきありがとうございます。
Smdn.dllのメソッドを呼び出そうとしてMissingMethodExceptionに なっていると思われます。
Smdn.dllおよびSmdn.Core.Standards.dllが実行ファイルと同じ場所に 配置されているかご確認ください。 (Smdn.Formats.Mime.dllだけでは動作しません)
>>90
早速のご回答ありがとうございました。 使いやすいライブラリを提供していただき、感謝しています。
ご教示どおりSmdn関連のライブラリをすべて、実行ファイルと同じ場所に配置し、 参照設定をし直して、リビルドなど、いろいろ試したのですが、 やはり、同じエラーが発生してしまいます。
メールサーバはMicrosoft Exchange Serverです。 当初、Smdn.Net.Imap4.Clientを使って、ImapMessageInfoの BodyStructureから添付ファイルを取得しようとしていたのですが、 Exchange Server 2007に不具合があり、サービスパック2を当てないと、 BodyStructureが壊れるとのMicrosoftの情報がありました。 (ExpressMailでは問題なく動いています)
「System.MissingMethodException はハンドルされませんでした。」 エラーもExchange Serverの不具合と関連している可能性はあるのでしょうか? なんらかのヒントをいただければ幸いです。
よろしくお願いいたします。
>>91
恐らくビルド済みパッケージをご利用のことかと思いますが、Smdn.Net.Imap4.Clientと Smdn.Formats.Mimeのバージョンの組み合わせ、または対象のフレームワーク (.NET 2.x or 3.5...)の組み合わせが一致しないためにMissingMethodExceptionが 発生しているかもしれません。
それぞれ最新のものを使っていれば発生しないと思いますが、参考までに 使用しているパッケージのファイル名をお教えいただけますでしょうか。
どうしても動作しないようなら、http://smdn.jp/works/tools/junk/SimpleMailer/ の ソースコードからビルドしてDLLを作成することで解決すると思います。
なおMissingMethodExceptionはライブラリ内部の問題で発生しているものなので Exchange Serverの不具合とは無関係のものです。
>>92
早速のご回答ありがとうございました。
Smdn関連のライブラリについて再度確認しましたところ、 .NET Framework 3.5のものと4.0のものとが混在しておりました。 すべて、3.5に統一することによって、正常に動作するようになりました。
お手数をおかけしましたが、これで解決しました。 ありがとうございました。
>>94
いえいえ、大変参考になります。ありがとうございます。 早速で申し訳ありませんが、1つ教えてください。
「BODYSTRUCTUREの参照」のサンプルコードでは、 列挙することで、マルチパートのネストに対応しているようですね。
その下方にある「メッセージに添付されているファイルを保存する例」 のサンプルコードでは、FindAll()メソッドを使っていますが、 マルチパートがネストしている場合を意識した処理は不要なのでしょうか? (ImapMessageFetchAttributeOptions.StaticAttributesを指定すれば大丈夫とか・・・)
お時間のあるときに、ご教示いただければ幸いです。 よろしくお願いいたします。
>>95
FindAll()メソッドはネストした構造を持つBODYSTRUCTUREの場合でも、その構造内を再帰的に走査します。
そのためFindAll()メソッドを使うにあたっては、BODYSTRUCTUREがマルチパートかどうか、 構造がネストしているかどうかを意識する必要はありません。
例えば、次のように多重にネストしている場合でも、セクション番号の順にすべてのセクションを走査します。
ImapMessageFetchAttributeOptions.StaticAttributesはImapMessageInfoの取得と同時に BODYSTRUCTUREの取得(FETCH)も行うことを指定するためのものです。 この値の指定はFindAll()メソッドの動作には影響しません。
ImapMessageFetchAttributeOptions.StaticAttributesを指定しない場合は、BODYSTRUCTUREを 取得していない状態となるため、ImapMessageInfo.BodyStructureプロパティを参照しようとした時点で 別途FETCHコマンドを送信し、BODYSTRUCTUREを取得しようとします。
一方ImapMessageFetchAttributeOptions.StaticAttributesを指定しておけば、一度のFETCHコマンドで BODYSTRUCTUREも同時に取得させるため、コマンドの送信回数を減らすことができます。
ImapMessageFetchAttributeOptions.StaticAttributesを指定した場合と、しない場合で ImapMessageInfo.BodyStructureプロパティの内容が異なるということはありません。
>>96
いつも明確で丁寧なご教示、ありがとうございます。 FindAll()はとても便利なメソッドですね。
早速「メッセージに添付されているファイルを保存する例」 サンプルコードに従って、C#でコーディングしたのですが、 結果は添付ファイルを認識できませんでした。
メールサーバはMicrosoft Exchange Server 2010 SP2、 Visual Studio 2008 (.NET Framework 3.5使用)ですが、 実際、下記の部分で、s.Disposition が「null」値になっているようです。
Exchange Server 2010 SP1は、Update Rollup 3を充てないと 正しいBodyStructureが返されないようです。 (http://support.microsoft.com/kb/2484862 )
Exchange Server 2010 SP2を使っているので、 問題ないと考えていますが、アドバイスをいただければ幸いです。
よろしくお願いいたします。
>>97
BODYSTRUCTUREにはContent-Dispositionヘッダを解析した結果が含まれる場合があり、 それを参照するためのプロパティがIImapBodyStructureExtension.Dispositionです。 メッセージパート内にContent-Dispositionヘッダがなければ、この値はnullとなります。
サンプルのIsAttachmentSection()では、コメントにもあるように「Content-Dispositionヘッダがあり、 かつ値がattachment」のパートを添付ファイルのパートと判断しています。
したがって、サンプルのIsAttachmentSection()では「Content-Dispositionヘッダが設定されて いない添付ファイル」は認識できません。
メールクライアントによってはContent-Dispositionヘッダが無くてもContent-Typeを見て 添付ファイルと判断するものもあるようですが、このサンプルではあくまでBODYSTRUCTUREの 解説ということでそういった複雑な判断は省略しています。
Content-DispositionとContent-Typeの両方から添付ファイルを認識する方法については、 Smdn.Formats.Mime.MailクラスのIsAttachedFile()メソッド(private)で実装していますので、 以下のファイルをご参照ください。
http://svn.smdn.jp/anonsvn/libs/Smdn/trunk/Smdn.Formats.Mime/Smdn.Formats.Mime/Mail.cs
また、仮にKBで指摘されている不具合に遭遇した場合は、ImapExceptionがスローされていると思います。 (サーバーがRFCに反する不正なレスポンスを返した場合は、InnerExeptionに ImapMalformedResponseExceptionが設定されたImapExceptionがスローされます) ですので、Exchange Serverから送信されるBODYSTRUCTUREには問題はないと思われます。
親切で丁寧なご回答ありがとうございました。
ご教示いただいたサンプルで試してみようと思います。
取り急ぎ、お礼のみにて失礼します。
管理人様
以下のWebサービスに対して、POP3通信ができない現象が発生しています。
こちらの呼び出し方法・設定に誤りがあるのでしょうか?
◎ 利用バージョン
◎ ソース
◎ 詳細 実際の通信を確認すると、以下の流れになりました。
上記のメールアドレス、パスワードはメールクライアントからは認証できることを確認しています。
>>101
ご利用いただきありがとうございます。
発生している問題の原因がつかめませんので、catch句でキャッチした例外の型と 例外メッセージ・スタックトレースなどの詳細をお教えいただけますでしょうか。
また、合わせて以下の2点についてご確認ください。
1) 本ライブラリでは、APOPコマンドでの認証に失敗した場合はUSERコマンドでの認証を試みます。 通信内容からは、APOPでの認証に失敗した後にUSERコマンドを送信していないように見えます。 USERコマンドが送信されているかどうか確認していただけますか?
2) 可能なら、お使いのメールクライアントで接続に成功する場合の認証方式の種類を 確認していただけますか?
>>101
早急なレスポンスありがとうございます。 最初の2つについて回答させていただきます。認証方式については確認させてください。
1) 例外メッセージは、以下になります。
2) USERコマンドの送信有無 送信していました。 その後、メールサーバからの応答はありませんでした。
3)
管理人様
過日は、いろいろとありがとうございました。 また、お世話になります。
【事象】
http://smdn.jp/works/libs/Smdn.Net.Imap4.Client/docs/#operation_examples_message_bodystructure
上記のような方法で、メッセージ全体の構造を取得し、添付ファイルを抽出する処理を組んでおりますが、 ImapMessageInfoのBodyStructureプロパティを参照するタイミングで、例外が発生してしまいます。 (通常は問題ありませんが、特定のメッセージに依存した問題のようです)
スタックトレースは以下のとおりです。
【質問1】 上記の事象が発生する原因と対策を教えてください。 (メッセージがいびつになっているので、添付ファイルは抽出できない?)
【質問2】 上記の事象が発生した後、INBOXにアクセスしようとすると以下の例外が発生します。
この事象が発生する原因と対策を教えてください。以下でよろしいでしょうか。 (原因:上記の事象により、接続が切れた。対策:IsConnectedプロパティがfalseなら再接続する。)
以上、ご教示いただければ幸いです。 よろしくお願いいたします。
>>103
頂いた例外メッセージを見たところ、APOP認証でエラーとなった時点でサーバー側から切断され、 さらにその後USERコマンドを送信しようとしてPopConnectionExceptionとなっているようです。
この動作自体には問題はありませんが、APOPに失敗した時点で切断している点が 疑わしいので、サーバー側のAPOP認証に関する設定を改めてご確認いただければと 思います。
もう一点、>>101 の通信内容から見てpop3UserNameに<メールアドレス>を 指定しているようですが、指定する値は<メールアドレス>であってますか? サーバーの設定によりますが、認証時のユーザー名としてメールアドレスの@以前を 指定するものと、メールアドレス全体を指定するものがあるので、その点をご確認ください。
>>104
管理人様
いつもお世話になっております。 動作環境を記入し忘れましたので、追記します。
.NETFramework4.0
ライブラリ
バージョン
Smdn.Core.Standards.dll
0.40.0.0
Smdn.dll
0.40.0.0
Smdn.Net.Imap4.Client.dll
0.90.0.0
Smdn.Net.Imap4.dll
0.90.0.0
Smdn.Net.MessageAccessProtocols.dll
0.90.0.0
Smdn.Security.Authentication.Sasl.dll
0.33.0.0
以上、よろしくお願いします。
>>104 ,106 こちらこそありがとうございます。 ユースケースからライブラリの不備や改善点を発見することが出来るので、 こちらとしても非常にありがたく思っています。
以下回答です。
【質問1の回答】 原因としてはサーバーから返送されるBODYSTRUCTUREの解析に失敗している可能性が考えられます。 ただ、返送されるBODYSTRUCTUREに問題があるのか、ライブラリ側の解析処理に問題があるのかは 判別できません。
発生した例外のInnerExceptionプロパティの内容と、BodyStructureプロパティを参照したときの 送受信ログを提示していただければと思います。
現状でのこの問題への対策は、例外が発生するメッセージの場合はBodyStructureプロパティを 参照しないようにするほかありません。 (0.90以降のSmdn.Net.Imap4.Client.dllでも同様の例外が発生すると思われます)
【質問2の回答】 原因・対策ともにご推察の通りです。
上記のような予期しない内部エラーが発生した場合は、正常に処理を継続できる保証がないため 内部的に接続を切断するようにしています。 そのため、内部エラーが発生したクライアントは切断状態となり、それ以降は操作を 行おうとすると例外InvalidOperationExceptionをスローするようになります。
このような場合は再接続して処理をやりなおす必要があります。
>>105
回答ありがとうございます。
メールクライアントで接続に成功する場合の認証方式は「平文のUSER/PASS 認証」です。 その際のUSERには、メールアドレスが指定されています。 (メールクライアントは、Thunderbird)
成功する場合の流れは以下になります。
推測ですが、メールサーバ自体がAPOPを受け付けないようにみえます。 設定等でAPOPにアクセスさせずに、平文のUSER/PASS 認証をさせることはできるのでしょうか?
よろしくお願いします。
>>108
この部分について確認させていただきたいのですが、"+OK "に続く文字列は "<process-ID.clock@hostname>"のように山カッコ<>でくくられた文字列でしょうか、 それとも山カッコを含まない文字列でしょうか。
もし山カッコでくくられた文字列(timestampと呼ばれます)であれば、 サーバーがAPOPをサポート・許可していることを表します。 (この場合、許可しているにも関わらず認証が失敗していることになります)
現在のバージョンでは、timestampを返送してきた場合は常にAPOPでのアクセスを 試行するようになっています。 また、APOPアクセスを行わないようにする設定も 今のところは用意していません。
そういった設定を追加する必要があるか判断したいので、差し支えなければ サーバーが返送してくる具体的な文字列をお教えいただければと思います。
なお、ソースコードを修正して対応する場合は、以下のファイルにある AuthenticateWithAppropriateMechanism()メソッドを修正することでAPOP認証を 行わないようにすることができます。
http://svn.smdn.jp/anonsvn/libs/Smdn/trunk/Smdn.Net.Pop3.Client/Smdn.Net.Pop3.Client.Session/PopSessionCreator.cs
>>109
"+OK "に続く文字列は、山カッコ<>でくくられた文字列です。
サーバーが返送してくる具体的な文字列は以下です。
現在の動作について分かりました。回答ありがとうございます。
>>110
情報提供ありがとうございます。 やはりサーバー側のAPOP認証処理に問題があるようです。 (サーバーはAPOP認証を許可しているものの、実際に試行するとエラーとなる) この問題はサーバー運営側にお問い合わせいただければと思います。
同時にSmdn.Net.Pop3.Clientの側でもAPOPを試行しないよう設定できるように しようと思います。
次のバージョン(今週末か来週中にリリース予定)にて対応予定ですが、 それまでの間はお手数ですが>>109 で提示した個所を修正することで 対応していただければと思います。
>>107
管理人様 いつもお世話になっております。
発生した例外のInnerExceptionプロパティの内容と、 BodyStructureプロパティを参照したときの送受信ログ が採れましたので提示させていただきます。
送受信ログは、最終行が本来、 C: 0024 UID FETCH 3 (BODYSTRUCTURE ENVELOPE INTERNALDATE RFC822.SIZE) となるべき所、上記のように尻切れトンボで終わってしまっています。
よろしくお願いいたします。
>>113
調査したところ、やはりUID FETCHに対するレスポンス部分のログを 見てみないことには問題個所の発見が難しいです。
なお、先ほどSmdn.Net.Imap4.Client version 1.04をリリースしました。 このバージョンではログが尻切れトンボになることはありませんので、 もしバージョンアップが可能でしたらこのバージョンでログを収集して いただければと思います。
>>115
さっそくのご回答ありがとうございます。 ログはTextWriterTraceListenerで出力したものです。 また、Smdn.Net.Imap4.Clientのバージョンアップありがとうございました。
バージョンアップしていただいたDLLで再度ログを取得しようと思います。 他のライブラリは>>106 のままで問題ありませんでしょうか?
以上簡単ですが、今後ともよろしくお願いします。
>>116
Smdn.Net.MessageAccessProtocols.dll
Smdn.Net.Imap4.dll
Smdn.Net.Imap4.Client.dll
上記3つのDLLだけバージョンアップしても動作するかもしれませんが、 確認はしていないので念の為すべて差し替えることをおすすめします。
>>117
お世話になっております。
Smdn.Net.Imap4.Client.dllのみをVer1.4に置き換えたことにより、 IMAPログは最後まで出力されるようになりました。
以下2つのDLLでエラーになってしまうので、 FETCHのレスポンス部分のログが出力されれば、 ほかのDLLを最新にしなくても、解析は可能でしょうか?
1.Smdn.Net.Imap4.dllを1.4に置き換えたところ、以下の例外が発生しました。
2.Smdn.dllを2.0に置き換えると、以下の例外が発生します。
お手数をおかけしますが、よろしくお願いします。
>>118
ログが収集できているようでしたら、Smdn.Net.Imap4.Client.dllのみの 差し替えでもかまいませんのでよろしくお願いします。
以下、個々に発生した問題に関して。
1.Smdn.Net.Imap4.dllを1.4に置き換えたところ、以下の例外が発生しました。
version 1.01でImapBodyDisposition.Filen ameプロパティをFileN ameに改名しています。 (http://smdn.jp/works/libs/Smdn.Net.Imap4.Client/releases/#changes_v1.01 )
恐れ入りますがImapBodyDisposition.Filen ameを参照している個所のソースの修正を お願いします。
2.Smdn.dllを2.0に置き換えると、以下の例外が発生します。
先日の>>91 -93の同様の問題で、恐らくSmdn.Net.MessageAccessProtocols.dllが .NET 3.5用のものになっているかと思われます。
.NET 4.0用と.NET 3.5用が混在していないか改めてご確認ください。
>>119
早速のご回答ありがとうございます。
それでは取り急ぎ、Smdn.Net.Imap4.Client.dllのみの差し替えで ログを収集し、結果は追ってご報告させていただきます。
個々の問題につきましては、ご教示のとおりでした。 1.FileNameに変更することで解決しました。 2.Smdn.Net.MessageAccessProtocols.dllが.NET 3.5用のものになっていました。
単純なミスでお手数をかけ、失礼しました。 今後ともよろしくお願いいたします。
>>120
いつもお世話になっております。
Visual Studio でdllを参照する設定をしているのですが、 やはり、Smdn.Net.Imap4.dllもバージョンアップしないと、 内部エラーが発生することがあるようです。
全てのdllを最新(2014/6/2リリースの.NET4対応版)にした上で、 近々ログを採取する予定です。採取できましたら、 ご連絡しますので、もうしばらくお待ちください。
いつもお世話になっております。
SimplerMailerを使ってみたいと考えております。 Visual Studioでは???ということですので、 Mono(C#用のIDEという認識でよろしいでしょうか?) のWindows版をインストールしてみようと思います。
Windows版のMonoでSimplerMailerを動かす場合の、 大まかな手順をご教示いただければ幸いです。
以上簡単ですが、よろしくお願いいたします。
>>122
いつもお世話になっております。
SimpleMailerを使うため、Ver1.02をダウンロードしました。 (環境が.NET Framework 4.0のため) また、Gtk#-2.12.9とMonoDevelop-3.0.6を ダウンロード、インストールしました。
MonoDevelopを起動して、SimpleMailerの.slnファイルを開き、 デバッグしようとしたところ、以下のエラーとなりました。
System.Runtime.InteropServices.COMException(0x80070032): この要求はサポートされていません(HRESULTからの例外: 0x80070032)
考えられる原因と回避策がありましたら、ご教示いただければ幸いです。 よろしくお願いいたします。
>>124
いつもお世話になっております。 さっそくのアドバイスありがとうございます。
【1】ターゲットアーキテクチャを32bitにする 【2】単に「デバッグなしで実行」する 【3】[STAThred]を削除する
【3】はご推察のとおり、関係ありませんでした。
【2】で動作はしますが、メールの仕組みを勉強したいので、デバッグはしたいです。 (ブレークポイントを設定したり、変数値を確認したり、といった操作)
【1】SimpleMailer.csprojがソリューションウィンドウに表示されなかったのですが、 「gui」-「Smdn.Applications.SimpleMailer」の右クリック-「オプション」で開く 「プロジェクトオプション」ダイアログの左ペインから、 「ビルド」-「カスタムコマンド」のプラットフォームには「AnyCPU」しか 表示されませんでした。
このため、SimpleMailer.csprojを直接テキストエディタで開き、 「AnyCPU」の部分を「x86」に置換して保存し、ソリューションを開きなおしましたが、 やはりデバッグの開始をしようとすると、同じエラーが表示されます。
ソリューションウィンドウの「gui」-「Smdn.Applications.SimpleMailer」が 「Smdn.Applicaions.SimpleMailer(not built in active configuration)」と 表示されているのも気になりますが、何度再ビルドしても表示は変わりません。
ターゲットアーキテクチャの変更方法に問題がありますか。
また、リンクでは、Monoのランタイムに置き換えればよい、といった記述もありますが、 それはどこにあって、何と置き換えればいいのか、わかりましたらご教示ください。
以上、ご多忙中恐縮ですが、よろしくお願いいたします。
>>125
いつもお世話になっております。 追加で恐縮ですが、教えてください。
SimpleMailer.iniで、
のように設定して実行したところ、下記のエラーになります。
Smdn.Net.Imap4.Client Information: 1 : CID:- connecting <ドメイン>の接続に失敗しました Exception: Smdn.Net.Imap4.Protocol.ImapConnectionException: connect failed ---> System.Net.Sockets.SocketException: 対象のコンピューターによって拒否されたため、接続できませんでした。
C#でメールを取得する処理では、
として、接続できています。
client.Profile.AllowInsecureLogin = true; の部分を、 SimpleMailer.iniで設定する方法をご教示いただければ幸いです。 (またはソースを修正する必要があれば、その方法)
以上、よろしくお願いいたします。
>>125
[ビルド]→[コンパイラ]→[一般オプション]下にある[プラットフォームターゲット]はどうでしょうか? これをx86にすればよいかと思います。
「置き換え」は使用するランタイムの切り替えを指すものと思いますが、 [編集](もしくは[ツール]?)→[設定]→[プロジェクト]→[.NETランタイム]で使用するランタイムを変えることができたと思います。
Windows環境で、かつVisual Studioが使用出来るのであればそちらを使ったほうが良いと思いますが、 MonoDevelopを使用される理由は何でしょうか? Visual Studioではソリューションの修正が必要になる以外の問題はないと思っていますが、 他に何か問題がありましたでしょうか?
>>126
現状SimpleMailer.iniでAllowInsecureLogin相当の設定を記述することはできません。 ImapAccountクラスを編集して、コード上でAllowInsecureLoginを設定するようにしてください。
>>127
いつもお世話になっております。 迅速なご回答ありがとうございます。
インストールしたMonoDevelopはVer.3.1.2で、 [ビルド]の配下に[コンパイラ]がなかったのですが、 「gui」-「Smdn.Applications.SimpleMailer」の右クリック-「オプション」 で開く「プロジェクトオプション」ダイアログの左ペインから、 「ビルド」-「コンパイル」にプラットフォームがありましたので、 これを「x86」に変更することで、デバッグができるようになりました。
なお、MonoDevelopに挑戦しようと思ったのは、Visual Studioでは、 ソリューション以外にも問題が出てきて、お手を煩わせたくなかっただけです。 問題がないのであれば、使い慣れたVisual Studioで行きたいと思います。
また、AllowInsecureLoginの設定については、ImapAccountクラスを編集して、 コード上で修正する必要がある旨、了解しました。
以上、簡単ですが今後ともよろしくお願いします。
>>128
いつもお世話になっております。 SimpleMailer-1.02を試しています。 (Visual Studioではすんなり動いてくれないので、 MonoDevelop 3.1.2 で動かしています)
上記のように、ImapAccountクラスを修正しましたが、 実行すると、下記のエラーとなります。
これだけでは足りないのでしょうか? ご教示いただければ幸いです。
>>129
AllowInsecureLoginの設定箇所自体は追加された個所で問題ありません。
しかし、>>126 と>>129 のエラーメッセージを改めて見たところ、 AllowInsecureLoginの設定とエラーの原因は無関係で、 接続確立の段階(認証処理を開始する以前の段階)で失敗しています。
接続先のアドレスとポートは127.0.0.1:143で合っているか、 ServerURLの設定が複数記述されていないかなど、iniファイルの内容を再度ご確認ください。
また、Visual Studioで動かない理由について、もしサンプルや ライブラリに問題があるなら修正したいと思いますので、 お教えいただけると幸いです。
>>121
管理人様 いつもお世話になっております。
過日の例外の事象で、ログが不足なく採取できましたので、提示させていただきます。 つきましては、原因と対策につきまして、ご教示いただければ幸いです。
【事象】(再掲) メッセージ全体の構造を取得し、添付ファイルを抽出する処理を組んでおりますが、 ImapMessageInfoのBodyStructureプロパティを参照するタイミングで、例外が発生。 (通常は問題なく処理できており、特定のメッセージに依存している模様)
【アプリケーションのログ】
【IMAP送受信ログ】
【動作環境】 .NET Framework4.0
ライブラリ
バージョン
Smdn.Core.Standards.dll
1.0.0.0
Smdn.dll
2.0.0.0
Smdn.Net.Imap4.Client.dll
1.4.0.0
Smdn.Net.Imap4.dll
1.4.0.0
Smdn.Net.MessageAccessProtocols.dll
1.4.0.0
Smdn.Security.Authentication.Sasl.dll
1.0.0.0
以上、ご多忙中恐縮ですが、よろしくお願いいたします。
>>133
いつもお世話になっております。 迅速なご回答、ありがとうございました!
早速、メールサーバ側に問い合わせを行いました。 取り急ぎ、以上ご連絡申し上げます。
>>135
管理人様。いつもお世話になっております。
ご連絡ありがとうございます。 対象フレームワークの情報が「製品名」で確認できるのですね。 (例:Smdn.Net.Imap4.Client-1.05-netfx4.0)
非常に助かります。今までは無理やりテキストエディタで開いて、 文字列「v4.0.30319」を検索していたものですから。
ついでの質問で恐縮ですが、教えてください。 現在利用中のVer.0.90を最新化(Ver.1.09)を検討中です。
その際、ソースの修正が必要なのは、 「ImapBodyDisposition.FilenameプロパティをFileNameに改名」 に対応する部分と考えており、リリース概要を見る限り、 他の修正は不要と考えておりますが、間違いないでしょうか?
以上、よろしくお願いいたします。
>>137
丁寧なご回答、ありがとうございます。
ひととおり最新版に入れ替えて、ビルドしたところ、 T[]からILIST<T>への変更に伴って、 以下の変更が必要になりました。
【変更前】
【変更後】
この変更は正しいでしょうか? fromAddr[0]の部分は変更していませんが、 同じ結果が得られるでしょうか?
C#の知識の問題かもしれませんが、 ご教示いただけると幸いです。
以上、よろしくお願いいたします。
>>138
その変更で問題ありません。
T[]からIList<T>に変更したことによりLengthの代わりにCountを 参照するよう変更する必要がありますが、リストに格納される内容と その格納順序はこれまでどおりで変更はありません。
従って、fromAddr[0]で得られる結果もこれまでと同じとなります。
>>139
いつもお世話になっております。 迅速なご回答ありがとうございます。
その他は、問題なく正常に動作しています。 取り急ぎ、ご報告させていただきます。 ありがとうございました。
お世話になります。 IMAPサーバーからIMAPサーバーへの移行を行うために、.netで移行ツールをこさえようとしています。 Smdn.Net.Imap4.Clientライブラリは、他にはないアカウント間のメールボックスの移行用メソッドがありますので、これを使いたい!とおもっています。
ドキュメントの「2.4 アカウント・サーバーをまたがるメールボックスの移動・コピー」のImapClientクラスに用意されているCopyMailboxメソッドの使用方法がわかりませんでしたので、ご相談させていただきたくて、投稿します。 VS2010でC#で開発中で、移行元をSrcClient、移行先をDstClientとしてIMAPClientを生成していますが、CopyMailboxメソッドをどのように使用すればよいかお教えください。
>>142
早速の回答ありがとうございます。できました。 これからもどうぞよろしくお願いします。
>>98
いつもお世話になっております。 だいぶ前の話で恐縮です。
上記でs.Dispositionが「null」値になっている場合、 Content-Typeを見て、添付ファイルと判断する処理を追加しようと考えています。
Smdn.Formats.Mime.MailクラスのIsAttachedFile()メソッド(private)での 実装を拝見しましたが、MimeMessageクラスに対する内容になっていました。
IImapBodyStructureないしIImapBodyStructureExtensionに対して判断する場合、 これらのクラスとMimeMessageクラスとの関係はどうなっていますでしょうか? アドバイスをいただければ幸いです。
以上簡単ですが、よろしくお願いいたします。
>>144
Content-DispositionとContent-Typeヘッダからどのように添付ファイルを判別するか という実装の例として提示させて頂いたものですが、MimeMessageとIImapBodyStructureは 互いに関連の無いクラスなので、そのまま呼び出して使うことはできません。
ただ、Content-TypeヘッダはIImapBodyStructure.MediaTypeプロパティ、Content-Dispositionヘッダは IImapBodyStructureExtension.Dispositionプロパティで参照できるので、このプロパティを 参照するように書き換えればこのメソッドの処理を流用できるかと思います。
参考までに、IsAttachedFileでは、Content-Dispositionが無い場合は以下のような判断を行なっています。
Content-Dispositionが無い場合最上位のmultipart/mixed配下にあるテキストパート(text/plain, text/html)は添付ファイルとみなさない (本文であるため) multipart/alternative配下にあるパートは添付ファイルとみなさない (代替コンテンツであるため)
本題とは離れますが、IImapBodyStructureに関して次のポストもご覧いただけると幸いです。
Smdn.Net.Imap4.Client.dllでは、この先のバージョンにてIImapBodyStructure関連のインターフェイスを 整理しなおそうと考えています。
これまで直接IImapBodyStructureを参照する必要があって分かりづらかったものを、以下のような クラスを追加してより使いやすい形にしようと考えています。 (現行バージョンでIImapBodyStructureを直接参照しているメンバは、新しいクラスを追加する際に 非推奨とし、そのしばらく後に削除する予定です)
もし現行のIImapBodyStructure関連で不便な部分や必要な機能がありましたらお教えください。 新しいクラスを作成する際の参考にさせていただきたいと思います。
現行バージョンでのサンプル
現在検討中のクラス案
>>145
いつもお世話になっております。 早速のご回答ありがとうございました。 参考にさせていただきます。
>>146
要望について記述します。
1.Content-Dispositionヘッダが無くても、 添付ファイルを取得できるような機能
2.添付ファイル名を取得できる機能
以上の機能があると嬉しいです。
私は、Smdnライブラリを利用した、添付ファイル抽出プログラム の修正を担当しているのですが、現行のIImapBodyStructure関連では、 添付ファイル名の復元にかなり苦労しているようです。
具体的には、ファイル名部分が通常文字の場合と16進数の場合に分け、 16進数の場合はデコードし、ファイル名が復元できない場合は、 固定ファイル名で保存し、といった処理にかなりのステップ数を割いています。
以上簡単ですが、今後ともよろしくお願いいたします。
>>147
ご要望ありがとうございます。
1.Content-Dispositionヘッダが無くても、添付ファイルを取得できるような機能
どのようなインターフェイスにするかは検討中ですが、機能としては実装したいと思います。
2.添付ファイル名を取得できる機能
これに関しては、version 1.01 (>>100 )にて提示させて頂いたImapBodyStructureUtils.GetContentFileName()メソッドを 使うことにより、現行バージョンでもヘッダからデコード済みのファイル名を取得できると思うのですが、 このメソッドでは機能に不足がありましたでしょうか?
GetContentFileName()相当の機能を新しいクラスで実装しようと考えているので、 このメソッドで対応できない場合、あるいは現在実装で苦労している部分(特に「16進数の場合」について)を お教えいただけると幸いです。 可能なら対応したいと思います。
>>148
早速のご回答ありがとうございます。
現在、稼働中のプログラムは、Ver0.90ベースで開発されていますので、 ImapBodyStructureUtils.GetContentFileName()メソッドが使えなかっただけ、 だと思いますが、開発者の意図を確認してみる必要があり、少し時間がかかるかもしれません。
取り急ぎ、以上中間報告させていただきます。
>>132
管理人様: いつもお世話になっております。
過日のBODYSTRUCTURE取得時の例外の件についての後日談です。
ヘッダ情報が、以下のようになっている場合、
メールサーバから{-1}が返ってくることが判明しました。
ただし、このヘッダ情報は、RFC5321違反ということで、 メールサーバ側でも対応はしない、とのことでした。>>133 の方法で回避できそうですが、ひとまずは例外を捕捉して、 当該メールはスキップする方向で対応する予定です。
以上、取り急ぎご報告いたします。
>>150
続報ありがとうございます。
私見ですが、せめてNILを返すようにするのが妥当かと思うので、対応しないというのは残念です。
先に書いたとおり、ライブラリ側としてもこの件は対応なしとさせていただきますので、 恐れ入りますが何らかの方法で回避して頂ければと思います。
>>151
ご連絡ありがとうございます。
メールサーバ側で対応しない、と断言しているのでなく、 アプリ側で対応してもらえないか、という打診でした。 私の書き方が悪く、誤解を与えてしまい、失礼しました。
いずれにしても、せめてNILを返すようにしてほしいと、 メールサーバ側へは要望を出しておきました。
以上簡単ですが、今後ともよろしくお願いします。
>>148
いつもお世話になっております。 現在実装で苦労している部分(特に「16進数の場合」について)のロジックは以下の通りです。
メッセージのIImapBodyStructureExtensionにDispositionにFileNameプロパティが存在すれば、 それをそのまま添付ファイル名としていますが、存在しない(==null)場合、 以下のように添付ファイル名を取り出しています。 DispositionにFileNameプロパティが存在しない場合、すべてのkey-valueペアを探索し、 "filename"が含まれるkeyが見つかれば、対応するvalueからファイル名を以下のように組み立てる。 (見つからなければ、"name"が含まれるkeyが見つかれば、対応するvalueをファイル名とする。)
valueを'(シングルクォート)でsplitして格納した、string配列の第3要素(~[2])から 1文字ずつ取り出し、'%'か否かで、16進か通常文字かを判断した上、一旦byte配列に格納する。 byte配列をエンコードして、文字列としてのファイル名を復元する。 (ファイル名に使えない文字があった場合は、当該文字を削除する)
これ以外にも、CP1252だった場合の対応などがあります。
コードそのものはお客様情報になり、公開ができないこと、 私自身がロジックを理解しきっていないこと、などから 抽象的な説明となってしまい申し訳ありません。
不明な点がありましたら、ご教示いただければ、 可能な範囲でお答えする所存ですので、よろしくお願いします。
>>152
こちらこそ差し出がましいことを失礼しました。 また、要望として送っていただきありがとうございます。
くじら1号様。 以下はImapMessagePartInfoクラスを使って添付ファイルの抽出を行うサンプルです。
>>147 で頂いたご要望を反映していますので、今後version 1.11を導入する際の 検討材料としてお使いいただければと思います。
また、>>153 を読んだところ、ファイル名の取得以外にも現在ライブラリで実装されている 機能を使えば実現できる個所があったので、それも合わせて記載しています。 要求されている機能をすべて満たすには不十分かもしれませんが、一助となれば幸いです。
>>153
詳細な内容を頂きありがとうございます。
(以下、ImapBodyStructureUtils.GetContentFileName()メソッドと version 1.11に含まれるImapMessagePartInfo.GetContentFileName()メソッドに関して、 両方をまとめて述べます。 version 1.11時点ではどちらも同じ動作・同じ結果を返します。)
まず「16進数の場合」については、回答頂いた内容から察するにRFC2231形式の パーセントエンコードされたファイル名のことと思われますが、だとすると これについては既に対応しています。 (こちらで把握していない「16進数」の形式があるのかと思い、質問させて頂きました)
一方、「"name"が含まれるkeyが見つかれば―」の個所は、nameがContent-Typeの パラメータか、それともContent-Dispositionのパラメータかで話が変わってきます。 現在のGetContentFileName()メソッドでは、Content-Typeのnameパラメータからの ファイル名の取得には対応していますが、Content-Dispositionのnameパラメータには 非対応です。
ただ、Content-Dispositionのnameパラメータは添付ファイル名として扱うべき 値ではないので、その場合はGetContentFileName()で扱う必要はないと考えています。 このnameパラメータに関するロジックとは、どういったヘッダ内容を想定したものでしょうか? よろしければお教えいただければと思います。
その他、いただいた内容を見る限りでは、すべて現在の実装でカバーでき、 新たに対応が必要になりそうな個所はなさそう、といった感触です。
最後に、現時点(version 1.11まで)のGetContentFileName()メソッドでファイル名として 取得できるヘッダのパターンを記載しておきます。 現状ではこれが添付ファイル名として広く使われているパターンと把握していますが、 これではカバーできないパターン、あるいは対応に苦慮しているパターンがあれば、 GetContentFileName()メソッドでの対応を検討したいと思います。
(参考までに、GetContentFileName()メソッドは#1→#4の優先順位でファイル名を取得します。#1がなければ#2→#3→#4といった流れです。)
>>157
いつもお世話になっております。 ご丁寧な回答、ありがとうございます。
「"name"が含まれるkeyが見つかれば―」の個所は、Content-Dispositionのパラメータです。 ただ、こちらの"name"パラメータは、ファイル名に不適切とのこと、了解いたしました。
CP1252は、キリル文字などがファイル名に使われている場合の対応のようですが、 GetContentFileName()では、対応していますでしょうか? また、ハングルなどのUnicode文字の場合など、いろいろな想定が必要かと考えています。
GetContentFileName()で対応しているファイル名の種類について、 ご教示いただけますでしょうか?
以上、よろしくお願いします。
>>157
いつもお世話になっております。 ご丁寧な回答、ありがとうございます。
「"name"が含まれるkeyが見つかれば―」の個所は、Content-Dispositionのパラメータです。 ただ、こちらの"name"パラメータは、ファイル名に不適切とのこと、了解いたしました。
CP1252は、キリル文字などがファイル名に使われている場合の対応のようですが、 GetContentFileName()では、対応していますでしょうか? また、ハングルなどのUnicode文字の場合など、いろいろな想定が必要かと考えています。
GetContentFileName()で対応しているファイル名の範囲(一覧)について、 また、想定外のファイル名であった場合、どのような例外を返すのかなど、 ご教示いただけますでしょうか?
以上、よろしくお願いします。
>>159
まず文字コードに関して。
GetContentFileName()ではSystem.Text.Encodingクラスを使ってデコードを行うので、 対応可能な文字コードはEncodingクラスと同じとなります。 .NET FrameworkのEncodingクラスはCP1252に対応しているようなので、 GetContentFileName()もCP1252でエンコードされた値を扱えると思います。
「対応しているファイル名の範囲(一覧)」については、失礼ながら「範囲」が 何の範囲を指すのか、お聞きしたいことがわかりませんでした。 カバーできる文字コードの範囲という意味であれば、先に述べたとおりEncodingクラスと 同じ範囲となります。 (ハングル・Unicode文字に関しても同様に、Encodingクラスが扱えるものなら対応しています)
次に例外等について。 version 1.11現在では以下の二つのオーバーロードを用意しています。
2つ目のオーバーロードでthrowIfMalformedOrUnsupportedにtrueを指定した場合は、 次の二つの例外をスローする可能性があります。
FormatException (System名前空間)
不正な形式の場合
EncodingNotSupportedException (Smdn.Formats名前空間, NotSupportedExceptionを継承)
対応していない文字コードの場合
一方1つ目のオーバーロード、あるいは2つ目でthrowIfMalformedOrUnsupportedにfalseを指定した場合は、 上記の例外をスローする代わりにデコード前の生の値をそのまま返します。
また、selectFallbackEncodingに適当なコールバックメソッドを指定すると、 対応していない文字コードだった場合に使用するフォールバック用のEncodingを 選択できるようになっています。 (コールバックメソッドに関しては>>23 をご覧ください)
そのほか、>>157 で挙げたヘッダとパラメータの組み合わせがない場合は、nullを返します。 (この場合は例外をスローしません)
GetContentFileName()はデコードした結果については一切検証を行いません。 例えば、戻り値がファイル名として適切かどうかは呼び出し側で判断する必要があります。 (ファイル名としての検証・無害化の例は>>156 をご覧ください)
>>160
管理人様
大変丁寧なご回答ありがとうございました。 また、返事が遅くなって申し訳ありません。
「対応しているファイル名の範囲(一覧)」は、 ご想像通りカバーできる文字コードの範囲という意味です。 Encodingクラスと同じ範囲とのご回答、了解しました。
かなり複雑なコーディングで、迂闊に手を出せませんが、 状況が整えば、使い勝手の良い、最新のライブラリで シンプルにコーディングし直したいと考えています。
その際には、またご厄介になるかもしれません。
取り急ぎ以上簡単ですが、今後ともよろしくお願いします。
管理人様
ご無沙汰しております。 ライブラリの最新化は未だ実現できておりませんが、 ここ数週間でトラブルが繰り返されているため、ご教示ください。
メールサーバのIMAPサービスのCPU使用率が100%近くになってしまう事象が起きています。
この場合、プログラムから呼び出すSmdn.Net.Imap4.Clientライブラリによって 要求されるIMAP要求に対して、サーバがIMAP応答を返さなくなることが考えられますが、 ライブラリ側では、タイムアウトなどを検知して、プログラムに返す動きはありますでしょうか?
それとも、サーバがIMAP応答を返すまで、待ち続けることになるのでしょうか?
以上簡単ですが、ご教示いただければ幸いです。
>>163
さっそくのご回答ありがとうございます。
Smdn.Net.Imap4.Clientの要求と、CPU使用率の上昇 (具体的には、IMAPサービスのCPU使用率が90%以上) とは、ほぼ同時に起こっているので、どちらとも言い難い状況です。
サーバのCPU使用率の上昇中に、要求を行う場合、 ImapClient.ReceiveTimeoutプロパティを設定することで、 タイムアウトを検知できるとのこと、了解しました。
取り急ぎ、以上ありがとうございました。
>>163
いつもお世話になっております。
ちなみに、ImapClient.ReceiveTimeoutプロパティに 設定する値について、推奨値などございますか?
現在メールサーバ(ExpressMail)のSMTPの ソケット受信タイムアウトが180秒のため、 180,000(ミリ秒)を設定しようとしています。
アドバイスをいただければ幸いです。
いつもお世話になっております。 引き続きの質問で恐縮です。
繰り返し処理におけるメッセージのメッセージ番号、UIDの割り振りについて教えてください。 以下のようなコードで、"INBOX"のメッセージを"workFolder"にコピーする場合、
1.「foreach」の中でメッセージは"INBOX"内の 「メッセージ番号」「UID」どちらの 「昇順」/「降順」に処理されますか?
2."workFolder"内のメッセージには、コピーされた順に どのような「メッセージ番号」と「UID」が振られますか? 以上、ご教示いただければ幸いです。
>>165
ライブラリとしては特に推奨する値はありません。 サーバーの設定にあった値・負荷がかからない値であれば任意に設定いただけます。
>>166
1.GetMessages()の処理順について
処理される順序は不定です。
GetMessages()はサーバーからのレスポンスを受信した順でImapMessageInfoを列挙します。 レスポンスの順序は多くのサーバーではメッセージ番号順(昇順)になると思いますが、 IMAPの仕様としては明確な順序は定められてはいません。 そのため、確実に メッセージ番号順・UID順で処理したい場合はソートを行う必要があります。
2.コピー時に割り振られる番号について
コピーを行う(=メールボックスにメールを追加する)場合、追加されるメールには、 メールボックス内のメールに割り振られている最も大きいメッセージ番号に+1
した メッセージ番号が割り振られます。 (メールがない場合は1
が割り振られます)
一方UIDは+1
した値になるとは限りませんが、メールボックス内で最後に 割り振られたUIDよりは大きい番号が割り振られます。
参考までに、ImapOpenedMailboxInfo.NextUidプロパティを参照すると、次回メールボックスに メールが追加される際に割り振られるUIDを知ることができます。
5.2.1.5 メールボックスの状態の取得http://smdn.jp/works/libs/Smdn.Net.Imap4.Client/docs/#operation_reference_mailbox_status
>>167
いつもお世話になっております。 迅速で丁寧なご説明、ありがとうございました。
内容について了解しました。 メールの同一性の判断には、Message-IDを取得して 行うようにします。
ありがとうございました。
管理人様、はじめまして。ぽこりんと申します。 数日前より Smdn.Net.Imap4.Client 最新版を利用させていただいております。 IMAPでのメール受信が簡単にでき、大変助かっております。
Gmail と Yahoo! メールで試していて、疑問と解決できない点がございますので、 お時間のあるときにご確認いただけましたら幸いです。
ドキュメントサンプルを参考に、Visual Studio 2012 で下記のコードで検証しています。
上記を Yahoo!メール、Gmail でテストすると、
1) 未読があっても(*1)では 0(件)と表示されますが、(*3)では正しく未読のUIDが表示されます。 2) Yahoo!メールに限り、(*2)の inbox.GetMessages(ImapSearchCriteria.Unseen) で例外エラーが発生します。 ImapSearchCriteria の他の指定でもすべて同じエラーになります。
問題の解決方法をアドバイスいただければ幸いです。 何卒よろしくお願いいたします。
>>169
Smdn.Net.Imap4.Clientをご利用頂きましてありがとうございます。 以下、ご質問について回答します。
1)UnseenMessageCountが0となる サーバーによっては、メールボックスを開く際に未読メッセージ数を通知しないものがあります。 そのため、メールボックスに未読メッセージが存在する場合でもUnseenMessageCountが0となることがあります。 (このことはドキュメントに未記載だったので追記しておきました)
このようなサーバーでは、GetMessagesなどで実際に検索・列挙してみるまで未読メール数を 知ることができません。
2)GetMessages()でNullReferenceExceptionとなる 検証したところ、Yahoo!メールのサーバーが返送してくるレスポンスが不正な書式と なっていることが原因であることがわかりました。 (具体的には、SEARCHコマンドのレスポンス末尾に余計な空白が含まれる)
ライブラリ側ではなくサーバー側の問題なので、ライブラリ側の修正対応は行いません。 先ほどYahoo!メール側には問題内容の報告を行っておきましたので、恐れ入りますが Yahoo!メール側で問題が改善されるのをお待ちいただければと思います。
なお、ソースコードを修正することでも問題を回避することができます。 その場合は、以下の箇所を修正してください。 ただし、Yahoo!メールでは問題なく動作することは確認していますが、 他のメールサーバーでも正しく動作するかどうかは未検証です。
ファイル:Smdn.Net.Imap4.Client/Smdn.Net.Imap4.Protocol.Client/ImapDataResponseConverter.cs
メソッド:FromSearchOrSort
管理人様
早々にご回答を頂戴し、誠にありがとうございます。
1)UnseenMessageCount の件、了解致しました。
2)ご提示いただいたソースコードでビルドしたDLLで、正しく動作することを確認いたしました。Yahoo!メールでの利用を考えていますので、当面こちらで検証してみます。
こんなに早く問題が解決出来て、感謝の気持ちで一杯です。
今後ともよろしくお願いいたします。
管理人様
お世話になっております。先日はご回答いただきありがとうございました。
引き続き、YahooメールのIMAPで検証しております。
(*1)の部分で、パスワードの先頭文字が{の時に ImapAuthenticationException をキャッチします。
authentication failed "Invalid command or arguments" (result code:Bad)
先頭文字を英数字に変更することでエラー回避できました。
先頭文字に記号を使うのはIMAPのルール違反か分かりませんが、一応、
事象をご報告させていただきます。
今後ともよろしくお願いいたします。
>>172
ご報告頂きありがとうございます。
{ はIMAPコマンドの引数では特別な意味を持つため、エスケープせずに送信すると 例外に含まれているメッセージにあるように、コマンド解析エラーとなります。 (平文でのログイン時にはエスケープせずにパスワードを送信します)
なお、IMAPの仕様では、(平文ログインの)パスワードに{ を使うことは許可されていません。
管理人様
はじめまして。サイパンと申します。 Smdn.Net.Imap4.Clientを利用させていただいております。 ありがとうございます。
現在、Yahoo!メールのIMAPに対し、メールボックスの名前と通数の取得を 以下のコードで検証をしておりますが、その中で質問があります。
1)INBOXの名前がInboxからINBOXとなる ログからIMAPのコマンド実行結果を確認すると、 Yahoo!メールの場合、INBOXの名前は、"Inbox"と返ってきてるようですが FullNameで取得した結果は、全て大文字の"INBOX"と なりますが、これは仕様でしょうか? 2)INBOXのメール通数が0となる ログからIMAPコマンドの実行結果を確認すると、 正しいメール通数が返ってきているようですが、 ExistMessageCountは、常に0となってしまいますが、 解決策はありますでしょうか? (他のメールボックスは正しい値が入っています。)
別件として、もう1点お教え願いたいのですが、1回のFETCH時の サイズを決定していると思われる、 ImapFetchMessageBodyStreamクラスのDefaultFetchBlockSizeですが、 この値を変更する場合、ソースコードを直接変更するしか方法がないでしょうか?
以上、ご教示いただけると大変ありがたいです。
>>174
Smdn.Net.Imap4.Clientをご利用頂きありがとうございます。
ご質問頂いた内容のうち、(2)に関してはライブラリの不具合だったため、 先ほど修正を施したversion 1.13をリリースいたしました。
変更点の詳細は以下をご確認ください。http://smdn.jp/works/libs/Smdn.Net.Imap4.Client/releases/#changes_v1.13
また(1)についてですが、この動作は仕様です。 IMAPではINBOXに限りメールボックス名の大文字小文字の違いが無視されますが、 本ライブラリではINBOXを大文字に統一した上で管理しているため、 ImapMailboxInfo.FullNameなどのプロパティは常に大文字の"INBOX"を返す動作となっています。
最後に、ImapFetchMessageBodyStream.DefaultFetchBlockSizeはご推察の通り 1回のFETCHコマンドで取得する最大サイズとなっています。 現状この値を変更する場合はソースを直接編集し、コンパイルしなおす必要があります。 (コード上から実行時に変更することはできません。 また今のところそのような操作を 可能にする予定は考えていません。)
なお、この値はファイルが添付されているなど巨大なメールを受信する際に LOH(Large Object Heap)の断片化を引き起こさないようにするために 設定している値です。 変更される際はその点にご留意ください。
管理人様
早速のご回答と修正、LOHのアドバイスまでいただき、 ありがとうございます。
アドバイスを基に、使わせていただきます。
ご参考ですが、Yahoo!メールの場合、 SEARCHコマンドのクエリBEFOREとSINCEは、問題ないのですが、 SENTBEFOREとSENTSINCEは、 Yahoo!から正しいメールが返ってこないようです。 また、NAMESPACE拡張も、RFCとして正しいのか調べ切れておりませんが、 個人名前空間のセパレータにNILが入っており、 使わせていただいているライブラリが エラーを出力しておりました。 Yahoo!メールのIMAPは、ちょっと特殊かもしれません。
今後とも、よろしくお願いいたします。
>>176
ご報告ありがとうございます。 SENTBEFORE/SENTSINCEの動作は把握していないものでした。 NAMESPACEの問題と合わせて、ライブラリ側での対処が必要かどうか 今後検証します。
Yahoo!メールに関しては、SEARCHレスポンスでもRFC違反があることを 認識していますので、参考としてお知らせしておきます。 (詳細と対処法は>>170 、この問題はYahoo!メール側に報告済みなのですが、 現在のところ修正されていないようです)
管理人様
お世話になります。 早速version 1.13を使用させていただき、 INBOXのメール通数が取得できることを確認させていただきました。 ありがとうございます。
version1.12では、発生しなかったのですが、 ImapSearchCriteriaでSince又はBeforeを使用してメッセージを取得しようとすると、 ImapMessageInfoList.csの110行目でsequenceOrUidSetがNullとなり、 NullReferenceExceptionが発生するようになりました。
可能であれば、解決策をご教示いただけるとありがたいです。
よろしくお願いいたします。
>>178
ImapMessageInfoList.csでNullReferenceExceptionが発生する件は>>170 の(2)と同じ事象と思われます。 恐れ入りますが、>>170 の(2)にあるとおりにソースコードを修正してください。
以下は、先にご報告頂いた問題に関してです。 SENTBEFORE/SENTSINCEについてはサーバー側の問題のようなのでYahoo!メール側に報告しておきます。 NAMESPACE拡張についてはライブラリ側の不具合なので、今後のバージョンで修正します。
管理人様
お世話になります。
>>170 を見落としておりました。 お手数をおかけし、申し訳ありませんでした。
ご丁寧な対応、誠にありがとうございました。
管理人様
その後の状況をご報告いただき誠にありがとうございます。
Yahoo!の仕様を留意した上で利用させていただきたく思います。
今後ともよろしくお願いいたします。
管理人様
お世話になります。 また、ご質問があり、投稿させていただきます。 よろしくお願いいたします。
foreachにて、ImapMessageInfoListからImapMessageInfoを取り出せる数について、 稀にですが、ImapMessageInfoList.ToArray().Lengthと比較し、少ない事象が 発生しております。 具体的には、以下のコードとなります。
Subjectが10個表示されないときのimap.logには、 IMAP Verbose: 2 : 2015-02-27T22:17:07.9073699+09:00 CID:2 [183.79.79.172:993] S: * NO message error; can't fetch that message13 と記録されております。 メールボックス内には、メールが10通ありますので、 サーバ側にて、何かしらの不具合により、たまたま1通だけFETCHできず、 このような事象が発生しているようです。 この事象が発生した場合に、Exception等により検知する仕組みはありますでしょうか?
また、上記コードで、EnvelopeSubjectを取得しておりますが、 メールのサブジェクトが、Base64等でエンコードせずに、 ISO-2022-JP又はSHIFT_JIS等で直接日本語が記載されていた場合、 デコードは、失敗する認識でよろしいでしょうか? この場合、EnveloepSubjectには、サブジェクトをUnicodeを前提として 変換格納しているのでしょうか?
メールによっては、サブジェクトがエンコードされていないため、 EnvelopeSubjectが文字化けしており、この文字化けを 元に戻すために、質問させていただきました。
よろしくお願いいたします。
>>184
分けて回答します。
1)FETCHできる件数が少なくなる問題について 先に対処法ですが、ご報告頂いた事例の場合Exceptionとして検知することができません。 代わりに、以下のようにUIDごとにGetMessageByUidメソッドを呼び出すようにしてください。
以下は原因と対策について。 (問題の整理とメモを兼ねているので、不要なら読み飛ばして頂いて問題ありません)
頂いたコードとログを見る限り、foreachの際に送信されるFETCHコマンドに対して、 以下のようなレスポンスが返されていると思われます。
この場合の"* NO ..."のレスポンスはエラーではなくあくまで警告として 扱われるものであるため、現在の実装ではこのような警告のレスポンスに 対しては何も行いません(例外もスローしない)。
この事象のように要求したコマンドを完全に実行できない場合は、本来なら "XXXX OK ..."ではなく"XXXX NO ..."が最終的に返されるべきであり、 これもYahoo!メール特有の動作と思われます。
現状では、このような要求を行わないようクライアント側で対処する必要があります。 再現する条件が判明したらYahoo!側に報告しようとは思いますが、>>181 の件と同様に修正はなされないかもしれません。
>>184
続き。
2)BASE64等でエンコードされていないサブジェクトの復元について SubjectヘッダがBASE64等でエンコードされていない場合、EnvelopeSubjectには ヘッダの値のバイト表現をそのままstringに変換した生の 値が格納されます。 (Encoding.GetStringではなくString(SByte*)コンストラクタで直接文字列化した 値が格納されているとイメージしてもらえればと思います)
BASE64等でエンコードされておらず、かつ、もとの文字コードが既知の場合は、 次のようなコードによって復元することができます。
管理人様
お世話になります。
早急で詳細な回答、まことにありがとうございます。
事象が稀にしか発生せず、その条件も不明のため、 検証が思うようにいかず、困っておりましたので、 解説までいただき、大変助かります。
管理人様からお教えいただいた方法で、 試してみたいと思います。
私からも、気づいた点等あれば、 またご報告させていただきます。
ありがとうございました。
管理人様
C# でのメール認証プログラムを検討していたところ、こちらのサイトにたどり着きました。 Smdn.Net.Pop3.Client や Smdn.Security.Authentication.Sasl の利用を考えているのですが、 こちらのライブラリは商用利用可能でしょうか?
管理人様
丁寧で素早い返答ありがとうございます。 まだ検討段階ですがお世話になるかもしれません。 今後ともよろしくお願いします。
管理人様 はじめまして
件名が euc-jp の Qエンコードだと文字化けしてしまします。 こちらのコードの問題なのか、対応外なのかご教授いただければ幸いです。 コードは下記のようにしています。
>>191
ライブラリをご利用いただきありがとうございます。
euc-jp の Qエンコードには対応しています。 また使用されているコードにも問題はありません。
ヘッダの内容に問題があると思われますので、差し支えなければ 読み込もうとしているメールのSubjectヘッダの内容を書き込んで 頂けますでしょうか。
>>192
管理人様 返信ありがとうございます。
ご指摘の通り、euc-jp の Qエンコードされた件名でも 文字化けするものとしないものとがありました。 文字化けした件名は下記になります。
よろしくお願いします。
>>193
ありがとうございます。
ご提示頂いたSubjectヘッダの内容に問題があり、この場合、 文字化けしてしまうのが本ライブラリの動作となります。
具体的には、Subjectヘッダ中にあるQエンコードされた2つの文字列が、 マルチバイト文字の途中で分割されていることが原因です。 これはRFCの規定に反した正しくないエンコード方法で、本ライブラリでは 想定していないため必ず文字化けします。
原因についてはこちらの解説が詳しいです。http://d.hatena.ne.jp/unarist/20150321/1426933207
現状では、このような場合に発生する文字化けをライブラリ側で検出したり、 回避したりする方法は用意していません。 今後、これをどのように扱うか 検討します。
恐れ入りますが、メールの送信側で正しくエンコードするように対処してもらうか、 このような場合に文字化けすることをご理解頂いた上でご利用いただければと 思います。
>>192
管理人様 返信ありがとうございます。
エンコードが正しくなく、現在の動きが仕様ということで 承知いたしました。 ただ、Outlookでは正常に表示されるので気になった次第です。
今後のアップデートで対応して頂けると嬉しいです。
大変ご無沙汰しております。 先般は大変お世話になりました。
いつも、便利なライブラリを利用させていただき、 ありがとうございます。
今回は、メールの削除処理の効率化について教えてください。
現在、処理の終わったメールのMessage-IDを配列に保存しておき、 メールフォルダから、GetMessagesでメール一覧を取得したのち、 配列のMessage-IDに一致するものにDeletedフラグをつけています。
これでは、メール件数だけIMAP通信が発生してしまうため、 最初からMessage-ID配列に含まれるメール一覧を取得し、 まとめて、Deletedフラグを付けられたらいいのに、と考えています。
具体的には、 ImapMessageInfoList messages
messages.AddFlags(ImapMessageFlag.Deleted); のようなことをしたいと考えています。
<質問1> 上記のように、msgIdList[]のように文字列の配列は指定できないようですが、 何か他の検索条件の設定方法はありますでしょうか?
<質問2> Message-IDの配列による検索が難しいのであれば、 UIDの配列でも構わないと考えています。 実際、 ImapMessageInfoList messages
messages.AddFlags(ImapMessageFlag.Deleted); のような方法があるようですが、 処理が終わったメールのUIDをこのuidSetに、 追加登録していく具体的な方法を教えてください。
以上、よろしくお願いいたします。
>>198
追加情報です。 <質問1>について、ドキュメント・サンプルより、 以下の方法があることを見つけました。
ImapSearchCriteria isc = ImapSearchCriteria.New; foreach (string msgId in m_msgIdList){
} ImapMessageInfoList messages = openedMailboxInfo.GetMessages(isc); messages.AddFlags(ImapMessageFlag.Deleted);
ただし、StackOverFlowExceptionがライブラリ内部で発生することがあるようです。 (条件が6000件だった場合) 回避策がありましたら、ご教示ください。
上記の方法では、問題があるようでしたら、 <質問2>の方法も考える必要がありますので、 こちらの質問についても引き続きよろしくお願いします。
>>198
>>199
引き続きライブラリをご利用いただいてありがとうございます。
先に目的を実現するための方法を書くと、<質問2>のようにUIDを用いる必要があります。
UIDを格納したlong型の配列をImapOpenedMailboxInfo.GetMessages()メソッドに渡すことで、 そのUIDに該当するメッセージを取得することができます。 その後、AddFlags(ImapMessageFlag.Deleted)することにより、まとめてDeleteフラグを付けることができます。
以下で個々の質問に対する回答と実装例を掲載します。
<質問1>への回答
質問にて指摘されているとおり、ImapSearchCriteria.Headerメソッドでは配列(=複数の値)を検索条件として 設定することはできません。 これはIMAPのSEARCHコマンドの仕様に基づく制限です。
従って、複数のMessage-IDからそれに該当するメッセージすべてを取得したい場合は、>>199 で 書かれているようにOR演算子によって条件式を結合する必要があります。 求められている動作を実現するコードも>>199 のとおりとなります。
一方、StackOverFlowExceptionは発生するのはライブラリ側の問題で、まさに今回のように多数の条件式を 連結しようとする際に起こり得ます。 これは、コマンド送信の際に条件式の展開が再帰的に 行われることが原因です。 現時点での実装では、特に条件式が長大になるような場合において StackOverFlowExceptionを回避することは難しいです。
なお、仮にStackOverFlowExceptionが起きない程度に処理するメール数を減らした場合でも、 サーバー側にかかる検索負荷を考慮するとこの方法は最善ではありません。 UIDが既知の状態であれば<質問2>の方法の方がよいでしょう。
<質問2>への回答
冒頭で書いたとおり、UIDを格納したlong型の配列(あるいはList<long>など)を、ImapOpenedMailboxInfo.GetMessages()メソッドに 渡すことにより、そのUIDに対応する全てのメールを取得することができます。 (ImapSearchCriteria.Uidおよび、ImapSequenceSetを使う必要はありません)
具体的なコードは次のようになります。 例示の簡単化のため配列ではなくList<long>を用いています。
>>200
さっそくのご回答ありがとうございます。
UIDを格納したlong型の配列またはListを ImapOpenedMailboxInfo.GetMessages()メソッドに 渡すことで、一括取得ができること、了解しました。
便利な機能ですね。 さっそく利用しようとしたのですが、 当方の処理の都合で問題があることがわかりました。
処理の流れは以下のとおりです。
1.INBOXフォルダのメールをすべて、作業フォルダにコピーする (ただし、削除フラグ有りのものを除く) 2.作業フォルダのメールについて、繰り返し処理を行う。 処理済みのメールのMessage-IDを配列に追加する 3.INBOXフォルダのメールのうち、処理済のものを削除する
2の処理の部分で、取得できるUIDは、作業フォルダのものなので、 このUIDでは、3の処理で、INBOXフォルダのメールが削除できず、 メールを特定する情報として、Message-IDを使っています。
INBOXフォルダから作業フォルダにメールをコピーする際、 双方のフォルダのUIDを紐付けることができればいいのですが。 実際、1の処理は、以下のようにしています。
openedMailboxInfo = client.OpenInbox(); ImapMessageInfoList undeletedMessages = openedMailboxInfo.GetMessages(ImapSearchCriteria.Undeleted); undeletedMessages.CopyTo(workFolderName);
この際のIMAPログを出力したところ、以下のようになっています。
C: 0009 SELECT INBOX S: * FLAGS (\Answered \Flagged \Deleted \Seen \Draft $MDNSent)
1800 EXISTS
0 RECENT
OK [UIDVALIDITY 1470805234] UIDs valid
OK [UIDNEXT 19667] Predicted next UID
OK [UNSEEN 1] message 1 is first unseen
OK [PERMANENTFLAGS (\Answered \Flagged \Deleted \Seen \Draft $MDNSent)] limited
0009 OK [READ-WRITE] select completed C: 000a SEARCH UNDELETED S: * SEARCH 1 2 3 ・・・ 1800 000a OK search completed C: 000b COPY 1,2,3,・・・,1800 201608101700 ←作業フォルダ名 S: 000b OK [COPYUID 1470816059 17867:19666 1:1800] copy completed
双方のフォルダのUIDが出力されているようです。
<質問3>
openedMailboxInfo = client.OpenInbox(); ImapMessageInfoList undeletedMessages = openedMailboxInfo.GetMessages(ImapSearchCriteria.Undeleted); undeletedMessages.CopyTo(workFolderName);
上記のようにコピーを実施する際、 コピー元とコピー先のUIDを紐づいた形で 取得する方法がありますでしょうか?
以上、よろしくお願いします。
>>201
追加情報です。
とりあえず、<質問3>の方法を使わずに、 処理を早くすることができましたので、ご報告します。
<質問3>につきましては、いったんご放念ください。
まず、INBOXフォルダのメールをすべて、作業フォルダにコピーする際に、 UIDとMessage-IDの関連を連想配列で紐付けておきます。
削除する際には、Message-IDを元に、 連想配列か元となるUIDを見つけ、UIDの配列に追加して、 ご教示のあった方法で、まとめて削除フラグを付与します。
以上簡単ですが、今後ともよろしくお願いします。
>>201
>>202
目的とする処理に関してはすでに実装まで解決されておられるようですが、 コピー前後でのUIDの紐付けに関して、以下参考としてご覧ください。
作業フォルダへのコピー時のレスポンスは、ご推察のとおり「コピー元のフォルダにあるUIDが 17867〜19666のメールを、コピー先フォルダにコピーし、UIDとして1〜1800を割り当てた」という 意味になっています。
従って、プロトコル上はこれを元にしてコピー前後のUIDを紐付けできるようになっています。
しかし、現状のCopyToメソッドではこの情報をもとにしたUIDの紐付けは行えません。 これはCOPYUIDがIMAPの基本機能ではなく拡張機能であり(=この情報を返送しないサーバーも 存在しうる)、ライブラリの機能としてもいかに実装するか決めかねているためです。
将来的にはコピー前後で紐付けできるようにするか、少なくとも可能ならコピー後のUIDを 取得できるように改善しようと考えていますが、現時点では、コピー前後のメールを紐付け する場合はMessage-IDによって同定していただく必要があります。
>>203
ご参考情報をいただき、ありがとうございました。 たしかに、ExpressMailでは、Move拡張コマンドには対応してないようです。
いずれにしましても、GetMessages(UID配列)により、 対象のメールをまとめて取得することができ、 処理時間が劇的に改善でき、嬉しく思っています。
以上簡単ですが、今後ともよろしくお願いします。
>>204
いつもお世話になっております。
既知のUIDValidityとUIDから、メッセージを取得する方法について、 処理時間の短縮を検討しています。
現在は、GetMailBoxesメソッドにより、全フォルダを取得した上、 各フォルダについてループさせ、UIDValidityが一致した場合、 そのフォルダから、GetMessageByUidによりメッセージを取得しています。
上記の処理においてフォルダをループさせずに、 直接、UIDValidityから対象フォルダにアクセスする方法はないでしょうか?
GetMailboxに指定できる引数は、フォルダ名なので、上記は失敗しますが、 このような形で、できないでしょうか?
以上、よろしくお願いします。
>>205
UidValidity値は、IDやエイリアスのようなメールボックスを特定するための値ではないため、 UidValidityから対応するメールボックスを取得するような目的には使えません。 ライブラリとしてもそういった機能は提供していません。
従って、挙げられたコードのようにメールボックスをひとつずつ検査してUidValidityを チェックしていく必要があります。
(UidValidity値は、前回アクセスした時のUIDが現在も有効であるか、つまりメールとUIDの 対応関係が変化していないかどうかをチェックするための値です。 サーバー側の動作により メールボックスのUidValidity値が変わる場合があります。)
ところで、コード中ではUidValidityの取得のために各メールボックスをOpenしているように 見えますが、GetMailboxesではオプションでメールボックスのステータスも同時に取得することができます。
これによりUidValidityの検証のためにひとつずつメールボックスをOpenする必要がなくなるため、 処理時間の短縮が図れるかもしれません。
>>206
いつも迅速で的確なアドバイスをいただき、 ありがとうございます。
ご教示いただいた方法で、処理時間が半減しました。
また、UidValidity値について、私の認識が誤っていたことも ご指摘いただき、ありがとうございました。
取り急ぎ、以上です。
いつもお世話になっております。
今回は、Content-Dispositionヘッダに関して、 各メールソフトでの実装状況についての質問です。
添付ファイル名の判定にあたっては、 Content-Disposition: attachment; の filenameパラメータを取得するのが基本だと考えています。
ただし、メールソフトによっては、filenameパラメータがなく、 他のパラメータを参考にする必要になる場合があります。
Content-Disposition: attachment; のパラメータには、 filenameパラメータの他に、下記のものがあるようです。
creation-date [RFC2183] modification-date [RFC2183] read-date [RFC2183] size [RFC2183] name [RFC7578] voice [RFC2421] handling [RFC3204] preview-type [RFC7763]
調べた範囲では、以下のようでした。
【Mozilla Thunderbird】 filenameパラメータのみ
【Microsoft Outlook】 filenameパラメータ cteation-dateパラメータ modification-dateパラメータ sizeパラメータ
他のメールソフトについて、 Content-Disposition: attachment; の実装状況を ご教示いただければ幸いです。
あくまでも、現在ご存じの情報だけで構いません。
勝手なお願いで恐縮ですが、よろしくお願いします。
>>208
ご質問の「Content-Disposition: attachment; の実装状況」とは「filenameパラメータがない場合において、 添付ファイル名の代替として使用されるContent-Dispositionのヘッダパラメータにはどのようなものがあるか」という 趣旨かと推察いたしますが、各メールソフトの添付ファイル名の扱いがどうなっているか、 特にContent-Dispositionパラメータの利用例となると情報を持っていませんので、残念ながら ご期待に添える回答ができません。
直接の回答にはなりませんが、ライブラリの機能で添付ファイル名を代替的に決定する場合、という観点で 述べると >>156 にてひとつ例示していますので、改めてご覧いただければと思います。
(この例ではサブジェクトをファイル名に使用していますが、ユニークであることの保証が必要なのであれば Message-IDヘッダやContent-Typeヘッダのboundaryパラメータなどを組み合わせる、あるいは組み合わせた 値からハッシュ値を求めてそれを使う、などがよいかと思います。 ユーザーフレンドリな形式ではありませんが。)
以上、趣意と異なる回答となっていましたらすみません。
>>209
さっそくのご回答ありがとうございます。
各メールソフトの添付ファイル名の扱いについて、 情報をお持ちでないこと、了解しました。
また、根本的な改修の際には、ぜひとも、>>156 のサンプルを参考にさせていただく所存です。
取り急ぎ以上簡単ですが、今後ともよろしくお願いします。
こんにちは。 Gmailから、特定の条件に合致するメールを抽出するためのソフトを作りたく、ライブラリを利用させていただいています。 メールやC#の知識は乏しく、ドキュメントを見よう見まねでなんとか動かしている状況です。 本ライブラリを利用してやっていることは、メールのto,from,Body,subject,dateあたりをテキストでローカルDBに保存しておく、というだけの単純なものです。
GetMessagesGmailSearchで取得した ImapMessageInfo message に対して message.ReadAs<Mail>(Mail.Load) を実行すると、一部メールで 'cp932' is an unsupported or invalid charset という例外が発生します。 どうやらiPhoneから送られたメールの一部がこのような文字コードで送ってくるらしく、Web検索してみるとほかのメーラでも文字化けする現象がよくあるようです。
これは単純にcp932に対応していないため無理だということでしょうか? それとも何か対応策があるのでしょうか?>>52 に「cp932」というキーワードがあるので関連があるかと思ったのですが、内容が高度で理解できませんでした…
内容的には
というようなコードです。 Smdn.Formats.Mime.dll 0.39.0.0 Smdn.Net.Imap4.Client.dll 1.14.0.0 Smdn.Core.Standards.dll 1.1.0.0 すべて.NET4.5版 を使用しています。 よろしくお願いいたします。
>>211
ライブラリをご利用いただきありがとうございます。 事象としてはまさに >>52 の方と同様で、対処法は >>23 でも紹介していますが、改めて以下に記載します。
本ライブラリでサポートする文字コードは.NET Frameworkと同じで、.NET FrameworkのEncodingクラスが サポートしていない場合は今回のように例外が発生します。
本ライブラリでは、このような場合でも代用する文字コード(Encoding)を選択できるようにしています。(>>23 )
具体的なコードとしては、まず次のようなメソッドを用意します。
次に、読み込み時にこのメソッドを使うようにMail.Loadの引数で指定します。 ご提示頂いたコードの場合では、ReadAsメソッドの代わりにOpenReadメソッドを使うように変更する必要があります。
このようにすることで、CP932の場合もShift_JISとしてデコードすることができるようになります。
ただこの方法では、CP932をShift_JISとしてデコードすることになるため、特殊文字等で文字化けが 発生する可能性があります。 その点はご留意ください。
もしほかにご不明な点がありましたらお気軽にお問い合わせください。
>>212
ありがとうございます! サンプルどころかコピペで済むレベルでコードまで書いていただいて……解説も非常にわかりやすかったです。 頂いたコードで問題なくデコードできることを確認しました。 即日お返事いただきありがとうございました。
VB版DLLを使用してGmailからImapのメール取得を行っておりますが、 本文が文字化けてしまい上手く取得が出来ません。 以下の書き方に問題はありますでしょうか。
>>215 早急な返信ありがとうございます!
デコードされた状態の本文が必要な場合は、ImapMessageFetchBodyOptions.OmitHeader(ヘッダの省略)と同時にImapMessageFetchBodyOptions.DecodeContent(内容のデコード)を組み合わせて指定してください。
とありますが、
この部分で複数のオプションを組み合わせる方法があるのでしょうか? 複数のオプションを組み合わせる方法が見つけられず 度々の質問となってしまい申し訳ありませんが、ご教示頂けると幸いでございます。
>>216
上記質問をさせて頂きましたが、 オプションを足し算して、それをImapMessageFetchBodyOptions型にCastすることにより、 複数のオプションが指定できました。
ありがとうございました。
はじめまして。 こちらのライブラリを使用させて頂いており、大変感謝しております。
現在、Microsoft365に対してIMAP接続するプログラムを作成しておりますが、 ログイン(ImapClientのConnectメソッド)で以下のExceptionが起きております。
upgrading stream failed (callback: System.IO.Stream CreateSslStream(Smdn.Net.ConnectionBase, System.IO.Stream))
それも起きるときと起きない時があり、対応に苦慮しております。
そもそも動作状況にMicrosoft365が無いので、このライブラリを使用させて頂くこと自体 おかしいのかもしれませんが、解決の糸口になればと思い書き込みさせて頂きました。
お手数ですが、ご確認いただけますと幸いです。よろしくお願いいたします。
>>219
ライブラリをご利用いただきありがとうございます。
ご報告いただいた例外についてですが、例外メッセージを見る限りでは サーバーまたはライブラリのどちらに問題があるか判別できません。
そこで恐れ入りますが、原因特定のためにライブラリのバージョンを含む 環境情報と、例外が発生した際のログ、また可能であれば接続時に指定している パラメータをご提示いただけますでしょうか。
ログの収集については >>28 あるいは以下のページをご参照ください。https://smdn.jp/works/libs/Smdn.Net.Imap4.Client/docs/#logging
なお動作状況に関してですが、当方ではMicrosoft365での動作確認ができていないものの、 本ライブラリは一般的なIMAPサーバーであれば概ね動作すると見込んでいるので、 本不具合をクリアすればMicrosoft365でも動作するのではないかと思います。
>>221
情報をご提供いただきありがとうございます。
ログに関してですが、キャッチした例外のInnerExceptionを含めた 内容を 取得していただけますでしょうか?
InnerExceptionにupgrading stream failed
となった根本原因が含まれているので こちらの情報を知りたいと思っています。
再度のお願いで恐縮ですがよろしくお願いします。
>>222
失礼いたしました。
改めてログを取得しましたので、ご確認のほど、よろしくお願いいたします。
Smdn.Net.Imap4.Protocol.ImapSecureConnectionException: upgrading stream failed (callback: System.IO.Stream CreateSslStream(Smdn.Net.ConnectionBase, System.IO.Stream)) ---> Smdn.Net.Imap4.Protocol.ImapUpgradeConnectionException: upgrading stream failed (callback: System.IO.Stream CreateSslStream(Smdn.Net.ConnectionBase, System.IO.Stream)) ---> System.IO.IOException: リモート パーティがトランスポート ストリームを終了したため、認証に失敗しました。
場所 System.Net.Security.SslState.StartReadFrame(Byte[] buffer, Int32 readBytes, AsyncProtocolRequest asyncRequest)
場所 System.Net.Security.SslState.StartReceiveBlob(Byte[] buffer, AsyncProtocolRequest asyncRequest)
場所 System.Net.Security.SslState.CheckCompletionBeforeNextReceive(ProtocolToken message, AsyncProtocolRequest asyncRequest)
場所 System.Net.Security.SslState.StartSendBlob(Byte[] incoming, Int32 count, AsyncProtocolRequest asyncRequest)
場所 System.Net.Security.SslState.ForceAuthentication(Boolean receiveFirst, Byte[] buffer, AsyncProtocolRequest asyncRequest)
場所 System.Net.Security.SslState.ProcessAuthentication(LazyAsyncResult lazyResult)
場所 System.Net.Security.SslStream.AuthenticateAsClient(String targetHost, X509CertificateCollection clientCertificates, SslProtocols enabledSslProtocols, Boolean checkCertificateRevocation)
場所 Smdn.Net.ConnectionBase.CreateClientSslStream(ConnectionBase connection, Stream baseStream, X509Certificate2Collection clientCertificates, SslProtocols enabledSslProtocols, RemoteCertificateValidationCallback serverCertificateValidationCallback, LocalCertificateSelectionCallback clientCertificateSelectionCallback)
場所 Smdn.Net.Imap4.Client.ImapSslConnection.CreateSslStream(ConnectionBase connection, Stream baseStream)
場所 Smdn.Net.ConnectionBase.UpgradeStream(UpgradeConnectionStreamCallback upgradeStreamCallback)
--- 内部例外スタック トレースの終わり ---
場所 Smdn.Net.ConnectionBase.UpgradeStream(UpgradeConnectionStreamCallback upgradeStreamCallback)
場所 Smdn.Net.ConnectionBase.Connect(String host, Int32 port, Int32 millisecondsTimeout, UpgradeConnectionStreamCallback createAuthenticatedStreamCallback)
場所 Smdn.Net.Imap4.Protocol.ImapConnectionBase.Connect(String host, Int32 port, Int32 millisecondsTimeout, UpgradeConnectionStreamCallback createAuthenticatedStreamCallback)
--- 内部例外スタック トレースの終わり ---
場所 Smdn.Net.Imap4.Protocol.ImapConnectionBase.Connect(String host, Int32 port, Int32 millisecondsTimeout, UpgradeConnectionStreamCallback createAuthenticatedStreamCallback)
場所 Smdn.Net.Imap4.Protocol.Client.ImapConnection..ctor(String host, Int32 port, Int32 millisecondsTimeout, UpgradeConnectionStreamCallback createAuthenticatedStreamCallback)
場所 Smdn.Net.Imap4.Client.Session.ImapSession.Connect(String host, Int32 port, Int32 connectTimeout, Int32 sendTimeout, Int32 receiveTimeout, UpgradeConnectionStreamCallback createAuthenticatedStreamCallback)
場所 Smdn.Net.Imap4.Client.Session.ImapSession..ctor(String host, Int32 port, Int32 transactionTimeout, Int32 sendTimeout, Int32 receiveTimeout, Boolean handlesReferralAsException, UpgradeConnectionStreamCallback createAuthenticatedStreamCallback)
場所 Smdn.Net.Imap4.Client.Session.ImapSessionCreator.CreateSession(IImapSessionProfile profile, SaslClientMechanism authMechanismSpecified, UpgradeConnectionStreamCallback createSslStreamCallback, CancellationToken cancellationToken, ImapSession& session)
場所 Smdn.Net.Imap4.Client.Session.ImapSessionCreator.CreateSession(IImapSessionProfile profile, SaslClientMechanism authMechanismSpecified, UpgradeConnectionStreamCallback createSslStreamCallback, CancellationToken cancellationToken)
場所 Smdn.Net.Imap4.Client.ImapClient.CreateSession(ConnectParams params)
場所 Smdn.Net.Imap4.Client.ImapClient.<>c__DisplayClass74_0.<Connect>b__0()
場所 Smdn.Net.Imap4.Client.ImapClient.RunExclusively(Action operation, Boolean throwIfNotConnected)
場所 Smdn.Net.Imap4.Client.ImapClient.Connect(ConnectParams params)
場所 Smdn.Net.Imap4.Client.ImapClient.Connect(String password)
場所 ローカルの呼出元のため、省略
Smdn.Net.Imap4.Protocol.ImapSecureConnectionException: upgrading stream failed (callback: System.IO.Stream CreateSslStream(Smdn.Net.ConnectionBase, System.IO.Stream)) ---> Smdn.Net.Imap4.Protocol.ImapUpgradeConnectionException: upgrading stream failed (callback: System.IO.Stream CreateSslStream(Smdn.Net.ConnectionBase, System.IO.Stream)) ---> System.IO.IOException: リモート パーティがトランスポート ストリームを終了したため、認証に失敗しました。
場所 System.Net.Security.SslState.StartReadFrame(Byte[] buffer, Int32 readBytes, AsyncProtocolRequest asyncRequest)
場所 System.Net.Security.SslState.StartReceiveBlob(Byte[] buffer, AsyncProtocolRequest asyncRequest)
場所 System.Net.Security.SslState.CheckCompletionBeforeNextReceive(ProtocolToken message, AsyncProtocolRequest asyncRequest)
場所 System.Net.Security.SslState.StartSendBlob(Byte[] incoming, Int32 count, AsyncProtocolRequest asyncRequest)
場所 System.Net.Security.SslState.ForceAuthentication(Boolean receiveFirst, Byte[] buffer, AsyncProtocolRequest asyncRequest)
場所 System.Net.Security.SslState.ProcessAuthentication(LazyAsyncResult lazyResult)
場所 System.Net.Security.SslStream.AuthenticateAsClient(String targetHost, X509CertificateCollection clientCertificates, SslProtocols enabledSslProtocols, Boolean checkCertificateRevocation)
場所 Smdn.Net.ConnectionBase.CreateClientSslStream(ConnectionBase connection, Stream baseStream, X509Certificate2Collection clientCertificates, SslProtocols enabledSslProtocols, RemoteCertificateValidationCallback serverCertificateValidationCallback, LocalCertificateSelectionCallback clientCertificateSelectionCallback)
場所 Smdn.Net.Imap4.Client.ImapSslConnection.CreateSslStream(ConnectionBase connection, Stream baseStream)
場所 Smdn.Net.ConnectionBase.UpgradeStream(UpgradeConnectionStreamCallback upgradeStreamCallback)
--- 内部例外スタック トレースの終わり ---
場所 Smdn.Net.ConnectionBase.UpgradeStream(UpgradeConnectionStreamCallback upgradeStreamCallback)
場所 Smdn.Net.ConnectionBase.Connect(String host, Int32 port, Int32 millisecondsTimeout, UpgradeConnectionStreamCallback createAuthenticatedStreamCallback)
場所 Smdn.Net.Imap4.Protocol.ImapConnectionBase.Connect(String host, Int32 port, Int32 millisecondsTimeout, UpgradeConnectionStreamCallback createAuthenticatedStreamCallback)
--- 内部例外スタック トレースの終わり ---
場所 Smdn.Net.Imap4.Protocol.ImapConnectionBase.Connect(String host, Int32 port, Int32 millisecondsTimeout, UpgradeConnectionStreamCallback createAuthenticatedStreamCallback)
場所 Smdn.Net.Imap4.Protocol.Client.ImapConnection..ctor(String host, Int32 port, Int32 millisecondsTimeout, UpgradeConnectionStreamCallback createAuthenticatedStreamCallback)
場所 Smdn.Net.Imap4.Client.Session.ImapSession.Connect(String host, Int32 port, Int32 connectTimeout, Int32 sendTimeout, Int32 receiveTimeout, UpgradeConnectionStreamCallback createAuthenticatedStreamCallback)
場所 Smdn.Net.Imap4.Client.Session.ImapSession..ctor(String host, Int32 port, Int32 transactionTimeout, Int32 sendTimeout, Int32 receiveTimeout, Boolean handlesReferralAsException, UpgradeConnectionStreamCallback createAuthenticatedStreamCallback)
場所 Smdn.Net.Imap4.Client.Session.ImapSessionCreator.CreateSession(IImapSessionProfile profile, SaslClientMechanism authMechanismSpecified, UpgradeConnectionStreamCallback createSslStreamCallback, CancellationToken cancellationToken, ImapSession& session)
場所 Smdn.Net.Imap4.Client.Session.ImapSessionCreator.CreateSession(IImapSessionProfile profile, SaslClientMechanism authMechanismSpecified, UpgradeConnectionStreamCallback createSslStreamCallback, CancellationToken cancellationToken)
場所 Smdn.Net.Imap4.Client.ImapClient.CreateSession(ConnectParams params)
場所 Smdn.Net.Imap4.Client.ImapClient.<>c__DisplayClass74_0.<Connect>b__0()
場所 Smdn.Net.Imap4.Client.ImapClient.RunExclusively(Action operation, Boolean throwIfNotConnected)
場所 Smdn.Net.Imap4.Client.ImapClient.Connect(ConnectParams params)
場所 Smdn.Net.Imap4.Client.ImapClient.Connect(String password)
場所 ローカルの呼出元のため、省略
>>223
例外詳細のご提供ありがとうございます。
原因は特定できていないものの、以下のようにTLS 1.2を使用することで 接続できる可能性があります。 ですので、まずはこれを試してください。
ImapSslConnectionクラスについては以下を参照してください。https://smdn.jp/works/libs/Smdn.Net.Imap4.Client/docs/#connection_ssl
また、これは根本的な解決にはなりませんが、もし接続失敗するときに発生する 例外の種類が常に今回と同じものであり、かつ、何度かリトライすれば接続できる 状況なのであれば、以下のように接続できるまで接続を試行するという方法も とることができます。
以下は例外から推測できる原因についてです。
頂いたログから確認できる限りでは、SSL/TLSでの接続を開始する際に、 サーバー側から処理が中断されているようです。
その理由ははっきりしませんが、一つ可能性があるのが、TLS 1.0および1.1の廃止です。 (参考: https://docs.microsoft.com/ja-jp/microsoft-365/compliance/tls-1.0-and-1.1-deprecation-for-office-365 ) この場合、SslProtocols.Tls12を指定することで回避できます。
もう一つ、同時接続数などサーバー側での制限の可能性も考えられます。 この場合は、先に上げたコードのようにリトライすることで対応できます。
ただ、原因がTLSのバージョンなら、例外が起きる場合と起きない場合がある点が不可解で、 接続数等の制限が原因ならSSL/TLSのネゴシエーション途中で中断されている点が 若干不可解です。 このため、他に理由がある可能性も考えられます。
いずれにしても、少なくともサーバー側の理由で接続処理が中断されている ようなので、根本的な原因についてはサーバー側の設定等をご確認ください。
もし提示いただいた以外の例外がスローされるようなら、クライアント側の問題の 可能性もあるので、その場合はご相談ください。
>>223
調査、ありがとうございます。
ひとまず、TLS1.2の設定を入れてしばらく様子を見てみます。 もしまた例外が起こるようでしたら、リトライ処理を入れることも検討いたします。
いずれにしろ、後ほど結果をご報告いたします。
また、作者様の方で提供してほしい情報がありましたら、ご連絡いただければ、 できる範囲で対応いたしますので、お申し付けください。
引き続きよろしくお願いいたします。
>>226
お世話になっております。
ご教授頂いたTLS1.2を使用することでエラーが発生しなくなりました。 1週間ほど経過していますが、1度もエラーが発生しておりません。
大変助かりました。ありがとうございました。
今後ともどうぞよろしくお願いいたします。
>>227
結果をお知らせ頂きありがとうございます。 Microsoft365での動作に関する情報をいただけてこちらも助かりました。