POP は比較的古いプロトコルです。最初のバージョンは 1984 年に指定されました。現在も使用されているバージョンである POP3 は、1996 年に指定されました。それを試すために、Gmail POP3 サーバーに接続してみました。
最初のステップは、POP3 設定、つまりどのサーバーにどのポートに接続するかを調べることでした。 Google が私をここに導き、次の情報を見つけました。
pop.gmail.com
SSL が必要: はい
ポート: 995
SSL が必要であることが記載されています。これは、私が最後に POP をいじっていた 25 年前には扱っていませんでした。頭が痛くなるのではないかと心配していましたが、実際には何の困難もありませんでした。 Python ドキュメントの少しの助けを借りて、このコードに到達しました。
import socket import ssl hostname = 'pop.gmail.com' context = ssl.create_default_context() with socket.create_connection((hostname, 995)) as sock: with context.wrap_socket(sock, server_hostname=hostname) as s: print(s.version())
接続すると、使用されている SSL のバージョンがわかります... など。大成功!サーバーとの会話を開始します。
POP3 の公式 RFC から借用した、クライアントとサーバー間の POP3 会話の例です/
C: <open connection> S: +OK POP3 server ready <1896.697170952@dbc.mtview.ca.us> C: USER mrose S: +OK mrose is a real hoopy frood C: PASS secret S: +OK mrose's maildrop has 2 messages (320 octets) C: STAT S: +OK 2 320 C: LIST S: +OK 2 messages (320 octets) S: 1 120 S: 2 200 S: . C: RETR 1 S: +OK 120 octets S: <the POP3 server sends message 1> S: . C: QUIT S: +OK dewey POP3 server signing off (maildrop empty) C: <close connection>
最初に行われるのは、サーバーがクライアントに挨拶を送信することです。フレンドリー。そこで、サーバーからメッセージを受信するコードを追加します。
ソケットからデータを受信するように要求する場合は、バッファ サイズを指定する必要があります。ドキュメントでは、4096 などの 2 の累乗を推奨しています。サーバーからの多数の応答が一度に送信されます。そうしない人もいます。場合によっては、サーバーからのメッセージがサーバー読み取り中に壊れたり、さらにメッセージがある場合でもバッファーが最大まで満たされないことがあります。
POP3 の場合、メッセージが受信されたかどうかを判断する方法は、どのメッセージが受信されているかによって完全に異なります。ほとんどの場合、サーバーは 1 行のテキストを送信します。 (後でもう一度説明しますが、これらのメッセージには各行の末尾にキャリッジ リターンとライン フィード文字があります。) 応答が長くなる可能性がある特定のメッセージでは、完了を示す別の方法、つまり 1 行にピリオドを使用します。それ自体で。
import socket import ssl hostname = 'pop.gmail.com' context = ssl.create_default_context() with socket.create_connection((hostname, 995)) as sock: with context.wrap_socket(sock, server_hostname=hostname) as s: print(s.version()) data = s.read(4096) print(data)
再び走ると、挨拶が得られます。またまた大成功!行が "rn" (キャリッジ リターンとライン フィード文字) で終わっていることに注意してください。
読み取りメソッドにバッファ サイズを渡す必要があります。これにより、サーバーからデータを読み取るために使用できるサイズのバッファーが確保されます。ただし、一度にバッファーに入るデータの量は保証されません。これは、プロトコルには、メッセージがいつ完了するかを指定する何らかの方法が必要であることを意味します。考えられる戦略は数多くあります。 POP は 2 つを使用します。すべてのメッセージの行は rn で終わります。短い (1 行) メッセージの場合、必要なのはこれだけです。複数行の応答の場合、行のピリオドだけでメッセージが完了したことを示します。
TLSv1.3 b'+OK Gpop ready for requests from 2601:1c0:8301:b590:f408:d66a:3029:16ad dq2mb54750689ivb\r\n'
次に、サーバーとの通信を開始する必要があります。 I/O (または O/I) ループを作成します。ユーザー入力を取得してサーバーに送信します。おっと!文字列を直接送信することはできません。 TypeErrorが発生します。メッセージをバイトに変換する必要があります。 string encode() メソッドがそれを行います (utf-8 のデフォルトのエンコーディングは正常に機能します)。
それを実行するときだけ -- おっと、また!メッセージがサーバーに送信されても何も起こりません。クライアントからのメッセージも rn で終わる必要があることを忘れていたためです。もう 1 つの小さな調整により、次のことが得られます。
import socket import ssl hostname = 'pop.gmail.com' context = ssl.create_default_context() with socket.create_connection((hostname, 995)) as sock: with context.wrap_socket(sock, server_hostname=hostname) as s: print(s.version()) while True: data = s.read(4096) print(data) msg = input() + "\r\n" s.send(msg.encode())
これで実際にログインできるようになりました!
TLSv1.3 b'+OK Gpop ready for requests from 2601:1c0:8301:b590:f408:d66a:3029:16ad g4mb5147337iow\r\n' USER grokprogramming b'+OK send PASS\r\n' PASS trustno1 b'-ERR [AUTH] Application-specific password required: https://support.google.com/accounts/answer/185833\r\n'
OK、そのリンクをたどると、アプリケーション固有のパスワードを設定できるページが表示されます。私が遭遇した潜在的な障害の 1 つは、私の知る限り、アプリケーション固有のパスワードを作成できるようにするには、アカウントで 2 要素認証をオンにする必要があるということです。主の年である 2024 年に、なぜ 2 要素認証を有効にしないのでしょうか?言えません。今もそうしています。
アプリケーション固有のパスワード (スペースを削除することに注意してください) を使用して、ログインできます。次に、STAT コマンドを発行すると、メッセージの数とそれらの合計サイズが表示されます。その後、LIST コマンドを発行します。これにより、各メッセージの ID とサイズを含むメッセージのリストが返されます。
TLSv1.3 b'+OK Gpop ready for requests from 2601:1c0:8301:b590:f408:d66a:3029:16ad e18mb76868856iow\r\n' USER grokprogramming b'+OK send PASS\r\n' PASS baygdsgkmihkckrb b'+OK Welcome.\r\n' STAT b'+OK 263 14191565\r\n' LIST b'+OK 263 messages (14191565 bytes)\r\n1 2778\r\n2 2947\r\n3 6558\r\n4 9864\r\n5 35997\r\n6 45462\r\n7 45462\r\n8 63894\r\n9 11487\r\n10 74936\r\n11 74925\r\n12 11632\r\n13 32392\r\n14 74997\r\n15 51961\r\n16 15375\r\n17 46513\r\n18 21519\r\n19 15966\r\n20 27258\r\n21 28503\r\n22 35615\r\n23 86353\r\n24 280'
コードにバグが発生しました。 LIST の応答は複数行にわたるため、この場合は複数のバッファー読み取りが必要になります。メッセージ全体は、単独の行のピリオドで終わります。ここで、1 バッファー分のメッセージを受信しました。コードがループの次の反復に進み、バッファーから再度読み取るために、Return キーを押して空のメッセージをサーバーに送信する必要があります。
ユーザーがバッファから再度読み取るかどうかを常に選択できるようにコードを微調整します。また、最終的にサーバーから受信したバイトをデコードして、テキストがより美しく表示されるようにします。
import socket import ssl hostname = 'pop.gmail.com' context = ssl.create_default_context() with socket.create_connection((hostname, 995)) as sock: with context.wrap_socket(sock, server_hostname=hostname) as s: print(s.version()) while True: data = s.read(4096) print(data.decode()) while input("more? y/[n]: ") == "y": data = s.read(4096) print(data.decode()) msg = input("> ") + "\r\n" s.send(msg.encode())
ここでは、電子メールの取得と切断メッセージの送信を含む完全なセッションを示します。
> USER grokprogramming +OK send PASS more? y/[n]: > PASS trustno1 +OK Welcome. more? y/[n]: > STAT +OK 263 14191565 more? y/[n]: > LIST +OK 263 messages (14191565 bytes) 1 2778 2 2947 3 6558 <...> 260 41300 261 114059 262 174321 263 39206 . more? y/[n]: > RETR 1 +OK message follows MIME-Version: 1.0 Received: by 10.76.81.230; Thu, 28 Jun 2012 20:21:50 -0700 (PDT) Date: Thu, 28 Jun 2012 20:21:50 -0700 Message-ID: <CADBp03TWFOKcTOaK_0P7VV2GB+TZsoSd_W4G5nZKKs7pdk6cWQ@mail.gmail.com> Subject: Customize Gmail with colors and themes From: Gmail Team <mail-noreply@google.com> To: Grok Programming <grokprogramming@gmail.com> Content-Type: multipart/alternative; boundary=e0cb4e385592f8025004c393f2b4 --e0cb4e385592f8025004c393f2b4 Content-Type: text/plain; charset=ISO-8859-1 Content-Transfer-Encoding: quoted-printable To spice up your inbox with colors and themes, check out the Themes tab under Settings. Customize Gmail =BB <https://mail.google.com/mail/#settings/themes> Enjoy! - The Gmail Team [image: Themes thumbnails] Please note that Themes are not available if you're using Internet Explorer 6.0. To take advantage of the latest Gmail features, please upgrade to a fully supported browser<http://support.google.com/mail/bin/answer.py?answer=3D6557&hl=3Den&= utm_source=3Dwel-eml&utm_medium=3Deml&utm_campaign=3Den> .. --e0cb4e385592f8025004c393f2b4 Content-Type: text/html; charset=ISO-8859-1 more? y/[n]: y <html> <font face="Arial, Helvetica, sans-serif"> <p>To spice up your inbox with colors and themes, check out the Themes tab under Settings.</p> <table cellpadding="0" cellspacing="0"> <col style="width: 1px;"/> <col/> <col style="width: 1px;"/> <tr> <td></td> <td height="1px" style="background-color: #ddd"></td> <td></td> </tr> <tr> <td style="background-color: #ddd"></td> <td background="https://mail.google.com/mail/images/welcome-button-background.png" style="background-color: #ddd; background-repeat: repeat-x; padding: 10px; font-size: larger"> <a href="https://mail.google.com/mail/#settings/themes" style="font-weight: bold; color: #000; text-decoration: none; display: block;"> Customize Gmail »</a> </td> <td style="ba more? y/[n]: y ckground-color: #ddd"></td> </tr> <tr> <td></td> <td height="1px" style="background-color: #ddd"></td> <td></td> </tr> </table> <p>Enjoy!</p> <p>- The Gmail Team</p> <img width="398" height="256" src="https://mail.google.com/mail/images/gmail_themes_2.png" alt="Themes thumbnails" /> <p><font size="-2" color="#999">Please note that Themes are not available if you're using Internet Explorer 6.0. To take advantage of the latest Gmail features, please <a href="http://support.google.com/mail/bin/answer.py?answer=6557&hl=en&utm_source=wel-eml&utm_medium=eml&utm_campaign=en"><font color="#999"> upgrade to a fully supported browser</font></a>.</font></p> </font> </html> --e0cb4e385592f8025004c393f2b4-- . more? y/[n]: > QUIT +OK Farewell. more? y/[n]: >
Yet another great success! I was able to log in to the POP3 server and retrieve a message. The script in its current state is pretty flexible, but it requires a lot of work from the user. I'll make a few final tweaks to make interacting with the POP3 server a little easier: if the user starts a message to the server with a "!" it will be stripped out, but the script will read in data from the server until it gets to a period on a line by itself -- in other words, for commands with long responses. No "!" and the script will read in a single line, looking for the \r\n characters.
import socket import ssl hostname = 'pop.gmail.com' context = ssl.create_default_context() def read_until(s, eom): # read into the buffer at least once data = s.read(4096) # continue reading until end of message while data[-len(eom):] != eom: data += s.read(4096) # return incoming bytes decoded to a string return data.decode() def read_single_line(s): return read_until(s, b"\r\n") def read_muli_line(s): return read_until(s, b"\r\n.\r\n") with socket.create_connection((hostname, 995)) as sock: with context.wrap_socket(sock, server_hostname=hostname) as s: print(s.version()) print(read_single_line(s)) msg = input("> ") # empty msg will close connection while msg != "": if msg[0] == "!": msg = msg[1:] long = True else: long = False msg += "\r\n" s.send(msg.encode()) if long: print(read_muli_line(s)) else: print(read_single_line(s)) msg = input("> ") s.close()
以上がPython を使用して Gmail POPerver と通信するの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。