バグ日記:メールで写真を修正した方法

Weblogicで動作する内部システム、既製のメールテンプレート、プログラマー、バグがあります。 さて、メールクライアントは、文字のマークアップに挿入された画像を表示できない可能性が高いことをご存知でしたか?そのソースはdata:image/gif;base64



で始まりdata:image/gif;base64







たとえば、私は知りませんでした。 しかし、すでにそこにあるものは、その前に、実際には画像自体がなくても画像をHTMLマークアップに挿入できることさえ知りませんでした。 同じ.jspを使用して、印刷用、場合によっては電子メール用のページを作成しました。 その結果、レターはブラウザで正常に開き、電子メールクライアントには壊れた画像が表示されます。



これは、1つの解決策を見つけるプロセスに関する物語です。 さて、まず最初に。



日中、システムから送信された手紙には写真が表示されないという苦情がクライアントから寄せられます。 プロジェクトマネージャーがタスクを実行しましたが、彼はいつものようにすべてをくれました。 インターフェイスを介して確認すると便利でした。実際、Outlookでは、写真の代わりに正方形に赤い十字が付いた空白が表示されました。 コードで、同じ.jspテンプレートファイルが印刷用のドキュメントデータのコンパイルに使用されていることに気付きました。 その瞬間、私は手紙を得るためにすべてのビジネスロジックを踏む必要がないのは良いことだと思いましたが、印刷用の空白だけを見ることができます。 ブランクを開けると、すべてが美しく、そしてあるべき姿になりました。



このタスクは少し面白くなくなりましたが、誰がチャレンジを恐れていますか? まず、Outlookでレターのマークアップを表示する方法を探してインターネットをサーフィンしました。これは非常に高速でした。 マークアップで、base64のWebインターフェイスとは異なり、「+」の代わりの画像が「+」であることがわかりました。 最初の推測は、HTML空白をSMTPサーバーに送信するメソッドがいくつかの特殊文字を除外することでした。 これはそうではなく、 " email.send(); "までであり、文字列には必要なすべての文字が含まれていました。



この振る舞いの理由への指示のために良い会社に頼る時です。 しばらくして、著者が電子メールクライアントとの互換性についてそのような写真をチェックするリソースを見つけました。 彼が引用したタブレットでは、リンゴのクライアントだけが傷のない写真を見せていました。 彼の手紙のコードで、私は大切な「+」を見て、これが私の場合であることに気付きました。 彼は分析の発見について話した。 彼はまだそれを修正する必要があると言い、同時にすべてが以前は大丈夫だと不平を言った。



以前は、システムはOC4Jでスピンしていましたが、Weblogicに移行した後、相対パスもどこかに移動しました。 その方法のために、すでに述べた印刷用の空白にはエラーがスローされました。 同僚が印刷用の空白を修正しましたが、印刷が機能するため、誰も手紙に気付かないか、テストしませんでした。 .jspからの行が形成される方法を見つけましたが、少し深くなって何か面白いものが見つかりました。



送信者メソッド
 protected boolean sendHtmlEmail(String fromAddress, String fromName, String toAddress, String toName, String subject, String textContent, String htmlContent, String serverName, String serverPort, String serverPath, String docRoot) { boolean result = true; HtmlEmail email = new HtmlEmail(); try { // Setup email parameters email.setHostName(SMTP_HOST); email.setSmtpPort(SMTP_PORT); email.setCharset("UTF-8"); email.addTo(toAddress, toName); email.setFrom(fromAddress, fromName); email.setSubject(subject); // Add text body if (!"".equals(textContent)) { email.setTextMsg(textContent); } // Add HTML body with inline images if (!"".equals(htmlContent)) { // System.out.println("htmlContent src: " + htmlContent); Matcher matcher = ManagerBase.imageSrcPattern.matcher(htmlContent); //URL imageURL = null; String imageCID = null; while (matcher.find()) { //System.out.println("sendHtmlEmail:"); //System.out.println("imageURL done: " + imageURL.toString()); //ClassLoader classLoader = getClass().getClassLoader(); //File file = new File(classLoader.getResource("../../" + matcher.group(2)).getFile()); // File image = new File(docRoot + matcher.group(2)); // imageCID = email.embed(image/*, matcher.group( 2 )*/); // System.out.println("imageCID done:" + imageCID); // htmlContent = htmlContent.replaceFirst(matcher.group(2), "cid:" + imageCID); } //System.out.println("htmlContent done: " + htmlContent); email.setHtmlMsg(htmlContent); } // Build && send email //email.buildMimeMessage(); result = result && filterDebugMail(toAddress, errors); if (result == true) email.send(); } catch (Exception e) { // ......  ,   // ......        :) } return result; }
      
      







コード化された画像の前に使用されたように見えますか? はいと思いました。 しかし、CVSは、ファイルの最初のバージョンはすでにこのメソッドを使用していると教えてくれました。 しかし、何も、ほとんどすべてがすぐに準備ができています。 「cid」について読みましたが、すべて問題ありません。 だから私は思った...



ほとんどの場合2つすべてですが、問題の調査の開始から1時間が経過した可能性があります。 最後に何かをコーディングするときです。 まず、写真を見つける必要があります。 リソースでは、.docドキュメントテンプレートのみが奇妙です。 .jspのパックの隣のフォルダーで写真を見つけました。 OK、手放しますが、必要な写真をリソースにコピーします。そこから 、少なくとも標準のgetResource()を取得できます。 それではcidには何が必要ですか?



ああ! HtmlEmailの近くにはImageHtmlEmailレシーバーがあり、明らかに適しています。写真が必要です。 次に、最初の.jspをすべて分割して、メールの過去とほぼ同じにすることにしました(DRYについては知っていますので、ヒットしないでください)。 しかし、ガイドでは、src属性の値を「cid:[拡張子なしのファイル名]」に変更しました。 ファイルの名前ではないはずですが、 Matcherのパターンは既にimgタグ内のものを選択しているので、特に論理的に思えました。

次に、 Matcherシステムがリソースから正しいファイルを選択すると書いています。



開始する
 while (matcher.find()) { //   , src    cid:[ ] String cidInFile = matcher.group(2); //   String imageName = cidInFile.substring(cidInFile.indexOf(":")+1); //    String imageFullResPath = "/images/print/" + imageName + ".gif"; }
      
      







したがって、画像をemail.embed()詰め込む必要があります。このメソッドにはDataSourceが必要です。 良い、5つの新しいオープンタブ、新しい友人の新しいアイデアの企業にアピールします。 4つの本格的な実装クラスのうち、2つが興味深いものであることがわかりました-ByteArrayDataSourceFileDataSourceです。 ただし、このファイルにはパスの操作が含まれており、パスが原因で以前のソリューションがやり直されていたため、これを最後の手段として残しましょう。 コンストラクターのByteArrayDataSourceは、バイトの配列とデータ型を必要とします。 良いものへの別のアピール、別の7つのタブ。 間違っている場合は修正しますが、MIMEタイプを提供する必要があります。 gifがあります-「image / gif」。 実際には、 getResourceAsStream()およびapache-commons-ioの IOUtilsを使用してデータ配列を取得します。



これですべてが次のようになります。



途中
 while (matcher.find()) { //   , src    cid:[ ] String cidInFile = matcher.group(2); //   String imageName = cidInFile.substring(cidInFile.indexOf(":")+1); //    String imageFullResPath = "/images/print/" + imageName + ".gif"; //    ClassLoader classLoader = getClass().getClassLoader(); InputStream is = classLoader.getResourceAsStream(imageFullResPath); byte[] imageData = IOUtils.toByteArray(is); // embed  y DataSource DataSource ds = new ByteArrayDataSource(imageData, "image/gif"); String cid = email.embed(ds, imageName); }
      
      







特にデバッガーを操作したときにエラーが発生しなかったため、見た目はずっと良くなりました。 email.send() 、run- NullPointerException 、問題についてコメントしました 。 私のすべてが空ではないようですが、繰り返し試みても同じ結果になります。 NPEをスローするImageHtmlEmailのソースを見ることができる場所を示したのは良いことです。 うーん... NPEが投げることができるのはDataSourceResolverだけです。ImageHtmlEmailに関する3つのチュートリアルの 1つではありません。 さて、ここにあります-ではありません...あり、その中にあり、後者にもあります。



DataSourceFileResolverがありましたが、 DataSourceByteResolverがなかったため、必要なものを追加する試みは実装の選択で停止しました。

ここでは、 FileDataSourceの下に既に書き込まれているすべてを翻訳する無駄な試みの2時間をスキップします 。 しかし、最終的には、必死になって、画像のsrcが「cid」で始まる場合、 DataSourceFileResolverは私のDataSourceが何であるかは関係ないと考えました。



一般的に、最終バージョンは次のようになりました。



終わり
 protected boolean sendHtmlEmail(String fromAddress, String fromName, String toAddress, String toName, String subject, String textContent, String htmlContent, String serverName, String serverPort, String serverPath, String docRoot) { boolean result = true; ImageHtmlEmail email = new ImageHtmlEmail(); try { // Setup email parameters email.setHostName(SMTP_HOST); email.setSmtpPort(SMTP_PORT); email.setCharset("UTF-8"); email.addTo(toAddress, toName); email.setFrom(fromAddress, fromName); email.setSubject(subject); // Add text body if (!"".equals(textContent)) { email.setTextMsg(textContent); } // Add HTML body with inline images if (!"".equals(htmlContent)) { URL resurl = getClass().getResource("/"); URI resURI = resurl.toURI(); File resFolder = new File( resURI ); resFolder = resFolder.getParentFile(); DataSourceResolver resolver = new DataSourceFileResolver(resFolder); email.setDataSourceResolver(resolver); Matcher matcher = ManagerBase.imageSrcPattern.matcher(htmlContent); while (matcher.find()) { //   , src    cid:[ ] String cidInFile = matcher.group(2); //   String imageName = cidInFile.substring(cidInFile.indexOf(":")+1); //    String imageFullResPath = "/images/print/" + imageName + ".gif"; //    ClassLoader classLoader = getClass().getClassLoader(); InputStream is = classLoader.getResourceAsStream(imageFullResPath); byte[] imageData = IOUtils.toByteArray(is); // embed  y DataSource DataSource ds = new ByteArrayDataSource(imageData, "image/gif"); String cid = email.embed(ds, imageName); } // email ready, enjoy your transfer email.setHtmlMsg(htmlContent); } result = result && filterDebugMail(toAddress, errors); if (result == true) email.send(); } catch (Exception e) { // ......... } return result; }
      
      







私はそれがスキップされたことに注意する必要があると考えています、そして実際、〜6行のコードが必要です:



-6時間の労働時間

->チュートリアル、StackOverflowなどを含む30のタブ

-ローカルビルドの3回ごとに1つの控えめな強い言葉

-> 30のローカルビルド



私が見つけた解決策について自分でメモを書きたかったのですが、突然誰か他の誰かがそれを見つけたら便利になります。



All Articles