Indyを使いgmailで送信する機能をIPv6に対応させるには?

解決


ミロ  2018-07-25 18:05:09  No: 49313

いつもお世話になっております。

iOSとAndroidでアプリにメールの送信機能を入れて開発をしています。 
OpenSSLを使いGmailを通して送信する機能です。
通りすがりさんに教えていただいた以下のリンク先を参考に実装しました。
>Indy 10 を使って GMail を送受信するには? (Delphi 2009 以降) 
https://ht-deko.com/tech040.html#tech076 

おかげさまで、実機でも動作確認ができて、Android版は、Google playに公開までたどり着けました。
次にiOS版をApp storeに公開するために、審査を受けました。
すると、このメール送信の機能がIPv6に対応しておらず、エラーになるので、修正して下さい、とのこと。
>We discovered one or more bugs in your app when reviewed on iPad and iPhone running iOS 11.4.1 on Wi-Fi connected to an IPv6 network.
どのように修正していけばよいのでしょうか?

開発環境は以下の通りです。 
PCはMacBook AirでMacOS10.12.6です。 
Parallelsを通してWindows10につないでいます。 
Delphi 10.2.3を使っています。 
どうぞよろしくお願いいたします。


IPv6  2018-07-25 19:04:16  No: 49314

iOS9 以降で必要な IPv6 only Network への対応
https://qiita.com/shao1555/items/4433803419dfc72bf80b

iOSアプリのIPv6での動作試験用のネットワークを作る
https://community.embarcadero.com/blogs/entry/ios-appstore-ipv6


ミロ  2018-07-25 22:24:09  No: 49315

IPv6さん

ありがとうございます。
>iOS9 以降で必要な IPv6 only Network への対応 
https://qiita.com/shao1555/items/4433803419dfc72bf80b 
「実際の対処方法」を確認しました。
1.まず検証環境の作るのですね。
有線LANケーブルが要るとのこと、帰りに買います。

2.アドレスファミリに依存しない実装
ここがダメで、審査が通らないのでしょうか?
今はきっとIPv4しか使えていないのですね。
>NSURLSession、CFNetworkレイヤーのAPIを使う。
このAPIが実装したもののどこに該当するのかから調べなくてはですね。

3.サービス名で接続するAPIを使う
少し調べましたが、何をしたらいいのかが分かりませんでした。


通りすがり  2018-07-25 22:46:26  No: 49316

"delphi indy ios ipv6"をキーワードに検索すると色々出てきますね。

Delphi iOS IPv6 trouble. Please ensure that your app is compatible with IPv6 networks - Stack Overflow
https://stackoverflow.com/questions/43242485/delphi-ios-ipv6-trouble-please-ensure-that-your-app-is-compatible-with-ipv6-net
Delphi iOS IPv6 App Store Rejection - Stack Overflow
https://stackoverflow.com/questions/39114096/delphi-ios-ipv6-app-store-rejection

ホスト名からIPアドレスを解決するときにIPv6を優先して使い、うまくいかなければIPv4で、
そしてIPv6で解決できたらIPv6で通信、というコーディングが必要だと思われます。


ミロ  2018-07-26 00:13:25  No: 49317

>通りすがりさん

ありがとうございます。
リンク先を拝見しあした。
教えていただいたあのGmailを送信するコードにどうやって反映させるかが分からずに困っています。
検証環境が無いので、まずはリンク先を参考に思いつくだけコードを書いてみます。


通りすがり  2018-07-26 04:49:37  No: 49318

このあたりあまり情報がないようですが、TIdSMTPのSocketプロパティにIPVersionというプロパティがあるので、
ホスト名(TIdSMTPのHostプロパティに設定するもの)を設定した後 IdSMTP.Connect; する前に 
IdSMTP.Socket.IPVersion := Id_IPv6; として、IdSMTP.Connectでエラー(例外)が発生したら 
IdSMTP.Socket.IPVersion := Id_IPv4; としてもう一度IdSMTP.Connectしてみる、みたいな
コーディングになるのではないでしょうか。
var
  Connected: Boolean;
begin
  IdSMTP.Host := 'ホスト名';
  IdSMTP.Port := ポート名;
  ...
  IdSMTP.Socket.IPVersion := Id_IPv6;
  try
    IdSMTP.Connect;
    Connected := True;
  except
    Connected := False;
  end;
  if Connected = False then
  begin
    IdSMTP.Socket.IPVersion := Id_IPv6;
  end;
こんな感じ?


通りすがり  2018-07-26 04:50:40  No: 49319

1行抜けてました。
var 
  Connected: Boolean; 
begin 
  IdSMTP.Host := 'ホスト名'; 
  IdSMTP.Port := ポート名; 
  ... 
  IdSMTP.Socket.IPVersion := Id_IPv6; 
  try 
    IdSMTP.Connect; 
    Connected := True; 
  except 
    Connected := False; 
  end; 
  if Connected = False then 
  begin 
    IdSMTP.Socket.IPVersion := Id_IPv6; 
    IdSMTP.Connect; 
  end;


通りすがり  2018-07-26 04:51:48  No: 49320

おまけに間違えてるし…たびたびすいません。
var 
  Connected: Boolean; 
begin 
  IdSMTP.Host := 'ホスト名'; 
  IdSMTP.Port := ポート名; 
  ... 
  IdSMTP.Socket.IPVersion := Id_IPv6; 
  try 
    IdSMTP.Connect; 
    Connected := True; 
  except 
    Connected := False; 
  end; 
  if Connected = False then 
  begin 
    IdSMTP.Socket.IPVersion := Id_IPv4; 
    IdSMTP.Connect; 
  end;


ミロ  2018-07-26 13:41:06  No: 49321

>通りすがりさん

自分流にやってみましたが、やはりよくわかりませんでした。
コードをありがとうございます。

教えていただいたコードを、「Indy 10 を使って GMail を送受信するには? (Delphi 2009 以降)」 に入れ込んでみました。
IPv4の環境では動きました。

検証環境を作るのがうまくいっておらずまだIPv6の環境で試せていない状況です。
取り急ぎお礼申し上げます。

念のためコードを載せておきます。
ユーザー名やパスワードは安全のために「xxxx」にしておきました。
このような形で良いのでしょうか?

//  以下、通りすがりさんのコードを入れ込んだメール送信機能
  Procedure MailSend;
  Var  Connected: Boolean;
  Begin
    IdSMTP := TIdSMTP.Create(nil);
    try
      IdSMTP.Host     := 'smtp.gmail.com';
      IdSMTP.Port     := 587;
      IdSMTP.Username := 'xxxx@gmail.com'; // UserName
      IdSMTP.Password := 'xxxx';       // Password
      SSL := TIdSSLIOHandlerSocketOpenSSL.Create;

      try
        SSL.Host := IdSMTP.Host;
        SSL.Port := IdSMTP.Port;
        SSL.Destination := SSL.Host + ':' + IntToStr(SSL.Port);
        IdSMTP.IOHandler := SSL;
        IdSMTP.UseTLS := utUseExplicitTLS;

        IdSMTP.Socket.IPVersion := Id_IPv6;
        try
          IdSMTP.Connect;
          Connected := True;
        except
          Connected := False;
        end;
        If Connected = False then
        Begin
          IdSMTP.Socket.IPVersion := Id_IPv4;
          IdSMTP.Connect;
        End;
        Msg := TIdMessage.Create(IdSMTP);
        try
          Msg.OnInitializeISO           := IdMessage_InitializeISO;
          Msg.ContentType               := 'text/plain';
          Msg.CharSet                   := 'UTF-8';
          Msg.ContentTransferEncoding   := 'BASE64'; // BASE64 (7bit)
          //Msg.ContentTransferEncoding   := '8bit';   // RAW(8bit)
          Msg.From.Name                 := SsNoSt;
          Msg.From.Address              := 'xxxx@gmail.com';
          Msg.Recipients.EMailAddresses := 'xxxx@gmail.com';
          Msg.Subject                   := SsNoSt;
          Msg.Body.Text                 := 'Unicode String (body)';
          IdSMTP.Send(Msg);
        finally
          Msg.Free;
        end;
        IdSMTP.Disconnect;
      finally
        SSL.Free;
      end;
    finally
      IdSMTP.Free;
    End;
  End;


ミロ  2018-07-26 17:17:28  No: 49322

>通りすがりさん
おかげさまで進みました。
android版は、IPv4もIPv6も繋がり、動きました。
iOS版は、IPv4では動きました。
IPv6には、実機(iPhone 6s plus)が上手く繋がりません。
androidは繋がるのにiPhoneで繋がらないのは、どういうことでしょう?

test−ipv6.comという接続性をチェックするサイトでは、iPhone 6s plusで以下のようなエラーメッセージが出ました。
ブラウザのアドオンとの干渉により、あなたのIPアドレスを検出できませんでした。
テスト結果によると、壊れた、もしくは正しくないIPv6設定になっており、webサイトがIPv6対応を行った際に問題が生じる恐れがあります。
他にもコメントがありましたので、改めて書き込みます。


ミロ  2018-07-27 14:50:28  No: 49323

こちらを参考にIPv6での動作試験用ネットワークを作りましたが、うまく行きません。
>iOSアプリのIPv6での動作試験用のネットワークを作る 
https://community.embarcadero.com/blogs/entry/ios-appstore-ipv6 
iPhone 6s PlusでブラウザはSafariを使っています。

test−ipv6.comという接続性をチェックするサイトでは、Android SH-01Kは繋がっていたようです。
iPhone 6s plusで以下のようなエラーメッセージが出ました。 

ブラウザのアドオンとの干渉により、あなたのIPアドレスを検出できませんでした。 
テスト結果によると、壊れた、もしくは正しくないIPv6設定になっており、webサイトがIPv6対応を行った際に問題が生じる恐れがあります。 

我々はあなたのシステムをテストできませんでした;ファイアウォール、もしくはブラウザフィルターがテストの動作を妨害しているようです。決定的に重要なテストが失敗しました。いかなるブラウザプラグイン、拡張、もしくはアドオン(例えば広告ブロックなど)を無効にして、このページを再読み込みしてください。それでも失敗するようであれば、支援を求める書き込みをコメントに残してください(英語のみ)。

開発環境は以下の通りです。 
PCはMacBook AirでMacOS10.12.6です。 
Parallelsを通してWindows10につないでいます。 
Delphi 10.2.3を使っています。 
どうぞよろしくお願いいたします。


IPv6  2018-07-27 20:57:04  No: 49324

想像ですけど、Macより先がIPv4ではないでしょうか?

https://qiita.com/kazinoue/items/e497db84d9b1c6327c50

IPv4もOKな状態だとIPv6の検証がしにくいので(IPv4で通信しようとしてしまう)、IPv6のみの環境作りが必要かと思います。


ミロ  2018-07-30 04:17:02  No: 49325

>IPv6さん

ご助言をありがとうございます。
たしかにmacより先(前)はIPv4です。

しかし有線LAN(IPv4)→Mac→wifi:IPv6→iPhone 6s plusという設定です。
Macの前の無線LANがIPv4というならおっしゃっていることにの影響がでるように思いますが、有線なので違うように思いますがいかがでしょうか。

リンク先の情報をありがとうございます。
難しそうですが読みといてみます。


ミロ  2018-07-31 15:09:01  No: 49326

>通りすがりさん

いつもお世話になっております。
書き込んでいただいたコードを追加して、上記のコードでAppleの審査を受けましたが、Rejectされました。
「アドレスsmtp.gmail.comの解決時にエラーが発生しました:(8)」とのエラーがIPv6環境で発生したとのことです。
このエラーは自分のIPv4環境でネットに繋いでいない時にも出ました。

アプリの機能として、このメールを送信する機能の後、グーグルフォームを開く機能が動くことになっています。
これもインターネットを通してやります。
https://www.gesource.jp/weblog/?p=6952
こちらのリンク先の以下のコードを使わせていただき実装しました。
加えて、IPv6に対応させるために、以下のリンク先のコードを加えて以下のように実装しました。
https://stackoverflow.com/questions/45215172/delphi-datasnap-connection-error-with-ipv6-ios 
すると、IPv4環境ではメール送信まではできますが、その先のグーグルフォームに繋ぐ際のところで、以下のエラーが出てしまいます。
「エラー  アドレス 00000001017C4334でアクセス違反が発生しました。(アドレス000000000000000へのアクセス時)」
ここからどのようにしていけば良いのでしょうか。
お忙しいところ恐縮ですがお知恵をお貸しいただけますとありがたいです。

//  Googleフォームを開く
  Procedure OpenGoogleForm;
  Var ipversion : String;
  Begin
    //  IPv6に対応させる
    IdTCPClient1.IPVersion:=Id_IPv4;  // <--  try IPv4 first
    IdTCPClient1.Host:=MY_IP;
    try
      IdTCPClient1.Connect;
      result:=true;
      ipversion := 'IPv4';      // <-- will tell us what ip version to use
    except
    end;

    if IdTCPClient1.Connected=false then
    begin
      try
        IdTCPClient1.IPVersion:=Id_IPv6;  // <--  now try IPv6
        IdTCPClient1.Connect;
        result:=true;
        ipversion:='IPv6';    // <-- will tell us what ip version to use
      except
      end;
    end;
    //  URLを開く
    {$IFDEF ANDROID}
    Intent := TJIntent.Create;
    Intent.setAction(TJIntent.JavaClass.ACTION_VIEW);
    Intent.setData(StrToJURI('https://docs.google.com/forms/d/e/1FAIpQLSfyNDVg4xjwdCT349wYB4W2f85tDry5m5ShGHFNdiUFinpcWQ/viewform?c=0&w=1'));
    SharedActivity.startActivity(Intent);
    {$ENDIF}

    {$IFDEF IOS}
    SharedApplication.openURL(StrToNSUrl('https://docs.google.com/forms/d/e/1FAIpQLSfyNDVg4xjwdCT349wYB4W2f85tDry5m5ShGHFNdiUFinpcWQ/viewform?c=0&w=1'));
    {$ENDIF}

  End;


ミロ  2018-08-02 13:10:17  No: 49327

>みなさま
マルチポストになるといけませんので、一旦こちらを閉じて、stackoverflowで質問をさせていただきます。
アドバイスを下さった通りすがりさん、IPv6さん、ありがとうございます。
続報がありましたら、こちらに書きこみます。


ミロ  2018-08-06 04:16:03  No: 49328

>みなさま

StackOverFlowにて助言を得られ、IPv6への接続についてはItunes Connectionの審査を通ったようです。
質問と回答のリンクを貼っておきます。
https://stackoverflow.com/questions/51640748/how-can-i-send-email-over-ipv6-properly
https://stackoverflow.com/questions/51643713/how-can-i-open-a-url-over-ipv6-properly


※返信する前に利用規約をご確認ください。








  このエントリーをはてなブックマークに追加