<span></span><span class="c1"># 导入 smtplib 以使用实际的发送函数</span>

    <span class="kn">import</span><span class="w"> </span><span class="nn">smtplib</span>

    <span class="c1"># 导入我们需要的 email 模块</span>

    <span class="kn">from</span><span class="w"> </span><span class="nn">email.message</span><span class="w"> </span><span class="kn">import</span> <span class="n">EmailMessage</span>

    <span class="c1"># 打开 textfile 中相应名称的纯文本文件供读取。</span>

    <span class="k">with</span> <span class="nb">open</span><span class="p">(</span><span class="n">textfile</span><span class="p">)</span> <span class="k">as</span> <span class="n">fp</span><span class="p">:</span>

    <span class="c1"># 创建纯文本消息</span>

    <span class="n">msg</span> <span class="o">=</span> <span class="n">EmailMessage</span><span class="p">()</span>

    <span class="n">msg</span><span class="o">.</span><span class="n">set_content</span><span class="p">(</span><span class="n">fp</span><span class="o">.</span><span class="n">read</span><span class="p">())</span>

    <span class="c1"># me == 发送方 email 地址</span>

    <span class="c1"># you == 接收方 email 地址</span>

    <span class="n">msg</span><span class="p">[</span><span class="s1">'Subject'</span><span class="p">]</span> <span class="o">=</span> <span class="sa">f</span><span class="s1">'The contents of </span><span class="si">{</span><span class="n">textfile</span><span class="si">}</span><span class="s1">'</span>

    <span class="n">msg</span><span class="p">[</span><span class="s1">'From'</span><span class="p">]</span> <span class="o">=</span> <span class="n">me</span>

    <span class="n">msg</span><span class="p">[</span><span class="s1">'To'</span><span class="p">]</span> <span class="o">=</span> <span class="n">you</span>

    <span class="c1"># 通过我们使用的 SMTP 服务器发送消息。</span>

    <span class="n">s</span> <span class="o">=</span> <span class="n">smtplib</span><span class="o">.</span><span class="n">SMTP</span><span class="p">(</span><span class="s1">'localhost'</span><span class="p">)</span>

    <span class="n">s</span><span class="o">.</span><span class="n">send_message</span><span class="p">(</span><span class="n">msg</span><span class="p">)</span>

    <span class="n">s</span><span class="o">.</span><span class="n">quit</span><span class="p">()</span>

    <span></span><span class="c1"># 导入我们需要的 email 模块</span>

    <span class="c1">#from email.parser import BytesParser</span>

    <span class="kn">from</span><span class="w"> </span><span class="nn">email.parser</span><span class="w"> </span><span class="kn">import</span> <span class="n">Parser</span>

    <span class="kn">from</span><span class="w"> </span><span class="nn">email.policy</span><span class="w"> </span><span class="kn">import</span> <span class="n">default</span>

    <span class="c1"># 如果 email 标头保存在文件中,则取消注释这两行:</span>

    <span class="c1"># with open(messagefile, 'rb') as fp:</span>

    <span class="c1"># headers = BytesParser(policy=default).parse(fp)</span>

    <span class="c1"># 或者如果要从字符串中解析标头(这是不太常见的操作),使用:</span>

    <span class="n">headers</span> <span class="o">=</span> <span class="n">Parser</span><span class="p">(</span><span class="n">policy</span><span class="o">=</span><span class="n">default</span><span class="p">)</span><span class="o">.</span><span class="n">parsestr</span><span class="p">(</span>

    <span class="s1">'From: Foo Bar <user@example.com></span><span class="se">\n</span><span class="s1">'</span>

    <span class="s1">'To: <someone_else@example.com></span><span class="se">\n</span><span class="s1">'</span>

    <span class="s1">'Subject: Test message</span><span class="se">\n</span><span class="s1">'</span>

    <span class="s1">'</span><span class="se">\n</span><span class="s1">'</span>

    <span class="s1">'Body would go here</span><span class="se">\n</span><span class="s1">'</span><span class="p">)</span>

    <span class="c1"># 现在标头条目将可作为字典访问:</span>

    <span class="nb">print</span><span class="p">(</span><span class="s1">'To: </span><span class="si">{}</span><span class="s1">'</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">headers</span><span class="p">[</span><span class="s1">'to'</span><span class="p">]))</span>

    <span class="nb">print</span><span class="p">(</span><span class="s1">'From: </span><span class="si">{}</span><span class="s1">'</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">headers</span><span class="p">[</span><span class="s1">'from'</span><span class="p">]))</span>

    <span class="nb">print</span><span class="p">(</span><span class="s1">'Subject: </span><span class="si">{}</span><span class="s1">'</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">headers</span><span class="p">[</span><span class="s1">'subject'</span><span class="p">]))</span>

    <span class="c1"># 你也可以访问地址的各个部分:</span>

    <span class="nb">print</span><span class="p">(</span><span class="s1">'Recipient username: </span><span class="si">{}</span><span class="s1">'</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">headers</span><span class="p">[</span><span class="s1">'to'</span><span class="p">]</span><span class="o">.</span><span class="n">addresses</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">.</span><span class="n">username</span><span class="p">))</span>

    <span class="nb">print</span><span class="p">(</span><span class="s1">'Sender name: </span><span class="si">{}</span><span class="s1">'</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">headers</span><span class="p">[</span><span class="s1">'from'</span><span class="p">]</span><span class="o">.</span><span class="n">addresses</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">.</span><span class="n">display_name</span><span class="p">))</span>

    <span></span><span class="c1"># 导入 smtplib 以使用实际的发送函数。</span>

    <span class="kn">import</span><span class="w"> </span><span class="nn">smtplib</span>

    <span class="c1"># 以下是我们要用到的 email 包模块。</span>

    <span class="kn">from</span><span class="w"> </span><span class="nn">email.message</span><span class="w"> </span><span class="kn">import</span> <span class="n">EmailMessage</span>

    <span class="c1"># 创建容器 email 消息。</span>

    <span class="n">msg</span> <span class="o">=</span> <span class="n">EmailMessage</span><span class="p">()</span>

    <span class="n">msg</span><span class="p">[</span><span class="s1">'Subject'</span><span class="p">]</span> <span class="o">=</span> <span class="s1">'Our family reunion'</span>

    <span class="c1"># me == 发送方 email 地址</span>

    <span class="c1"># family = 所有接收方的 email 地址列表</span>

    <span class="n">msg</span><span class="p">[</span><span class="s1">'From'</span><span class="p">]</span> <span class="o">=</span> <span class="n">me</span>

    <span class="n">msg</span><span class="p">[</span><span class="s1">'To'</span><span class="p">]</span> <span class="o">=</span> <span class="s1">', '</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">family</span><span class="p">)</span>

    <span class="n">msg</span><span class="o">.</span><span class="n">preamble</span> <span class="o">=</span> <span class="s1">'You will not see this in a MIME-aware mail reader.</span><span class="se">\n</span><span class="s1">'</span>

    <span class="c1"># 以二进制模式打开文件。 你也可以忽略子类型</span>

    <span class="c1"># 如果你想要 MIMEImage 自动猜测的话。</span>

    <span class="k">for</span> <span class="n">file</span> <span class="ow">in</span> <span class="n">pngfiles</span><span class="p">:</span>

    <span class="k">with</span> <span class="nb">open</span><span class="p">(</span><span class="n">file</span><span class="p">,</span> <span class="s1">'rb'</span><span class="p">)</span> <span class="k">as</span> <span class="n">fp</span><span class="p">:</span>

    <span class="n">img_data</span> <span class="o">=</span> <span class="n">fp</span><span class="o">.</span><span class="n">read</span><span class="p">()</span>

    <span class="n">msg</span><span class="o">.</span><span class="n">add_attachment</span><span class="p">(</span><span class="n">img_data</span><span class="p">,</span> <span class="n">maintype</span><span class="o">=</span><span class="s1">'image'</span><span class="p">,</span>

    <span class="n">subtype</span><span class="o">=</span><span class="s1">'png'</span><span class="p">)</span>

    <span class="c1"># 通过我们自己的 SMTP 服务器发送 email。</span>

    <span class="k">with</span> <span class="n">smtplib</span><span class="o">.</span><span class="n">SMTP</span><span class="p">(</span><span class="s1">'localhost'</span><span class="p">)</span> <span class="k">as</span> <span class="n">s</span><span class="p">:</span>

    <span class="n">s</span><span class="o">.</span><span class="n">send_message</span><span class="p">(</span><span class="n">msg</span><span class="p">)</span>

    <span></span><span class="ch">#!/usr/bin/env python3</span>

    <span class="sd">"""将目录的内容作为 MIME 消息来发送。"""</span>

    <span class="kn">import</span><span class="w"> </span><span class="nn">os</span>

    <span class="kn">import</span><span class="w"> </span><span class="nn">smtplib</span>

    <span class="c1"># 用于根据文件扩展名来猜测 MIME 类型</span>

    <span class="kn">import</span><span class="w"> </span><span class="nn">mimetypes</span>

    <span class="kn">from</span><span class="w"> </span><span class="nn">argparse</span><span class="w"> </span><span class="kn">import</span> <span class="n">ArgumentParser</span>

    <span class="kn">from</span><span class="w"> </span><span class="nn">email.message</span><span class="w"> </span><span class="kn">import</span> <span class="n">EmailMessage</span>

    <span class="kn">from</span><span class="w"> </span><span class="nn">email.policy</span><span class="w"> </span><span class="kn">import</span> <span class="n">SMTP</span>

    <span class="k">def</span><span class="w"> </span><span class="nf">main</span><span class="p">():</span>

    <span class="n">parser</span> <span class="o">=</span> <span class="n">ArgumentParser</span><span class="p">(</span><span class="n">description</span><span class="o">=</span><span class="s2">"""</span><span class="se">\</span>

    <span class="s2">Send the contents of a directory as a MIME message.</span>

    <span class="s2">Unless the -o option is given, the email is sent by forwarding to your local</span>

    <span class="s2">SMTP server, which then does the normal delivery process. Your local machine</span>

    <span class="s2">must be running an SMTP server.</span>

    <span class="s2">"""</span><span class="p">)</span>

    <span class="n">parser</span><span class="o">.</span><span class="n">add_argument</span><span class="p">(</span><span class="s1">'-d'</span><span class="p">,</span> <span class="s1">'—directory'</span><span class="p">,</span>

    <span class="n">help</span><span class="o">=</span><span class="s2">"""Mail the contents of the specified directory,</span>

    <span class="s2"> otherwise use the current directory. Only the regular</span>

    <span class="s2"> files in the directory are sent, and we don't recurse to</span>

    <span class="s2"> subdirectories."""</span><span class="p">)</span>

    <span class="n">parser</span><span class="o">.</span><span class="n">add_argument</span><span class="p">(</span><span class="s1">'-o'</span><span class="p">,</span> <span class="s1">'—output'</span><span class="p">,</span>

    <span class="n">metavar</span><span class="o">=</span><span class="s1">'FILE'</span><span class="p">,</span>

    <span class="n">help</span><span class="o">=</span><span class="s2">"""Print the composed message to FILE instead of</span>

    <span class="s2"> sending the message to the SMTP server."""</span><span class="p">)</span>

    <span class="n">parser</span><span class="o">.</span><span class="n">add_argument</span><span class="p">(</span><span class="s1">'-s'</span><span class="p">,</span> <span class="s1">'—sender'</span><span class="p">,</span> <span class="n">required</span><span class="o">=</span><span class="kc">True</span><span class="p">,</span>

    <span class="n">help</span><span class="o">=</span><span class="s1">'The value of the From: header (required)'</span><span class="p">)</span>

    <span class="n">parser</span><span class="o">.</span><span class="n">add_argument</span><span class="p">(</span><span class="s1">'-r'</span><span class="p">,</span> <span class="s1">'—recipient'</span><span class="p">,</span> <span class="n">required</span><span class="o">=</span><span class="kc">True</span><span class="p">,</span>

    <span class="n">action</span><span class="o">=</span><span class="s1">'append'</span><span class="p">,</span> <span class="n">metavar</span><span class="o">=</span><span class="s1">'RECIPIENT'</span><span class="p">,</span>

    <span class="n">default</span><span class="o">=</span><span class="p">[],</span> <span class="n">dest</span><span class="o">=</span><span class="s1">'recipients'</span><span class="p">,</span>

    <span class="n">help</span><span class="o">=</span><span class="s1">'A To: header value (at least one required)'</span><span class="p">)</span>

    <span class="n">args</span> <span class="o">=</span> <span class="n">parser</span><span class="o">.</span><span class="n">parse_args</span><span class="p">()</span>

    <span class="n">directory</span> <span class="o">=</span> <span class="n">args</span><span class="o">.</span><span class="n">directory</span>

    <span class="k">if</span> <span class="ow">not</span> <span class="n">directory</span><span class="p">:</span>

    <span class="n">directory</span> <span class="o">=</span> <span class="s1">'.'</span>

    <span class="c1"># 创建消息</span>

    <span class="n">msg</span> <span class="o">=</span> <span class="n">EmailMessage</span><span class="p">()</span>

    <span class="n">msg</span><span class="p">[</span><span class="s1">'Subject'</span><span class="p">]</span> <span class="o">=</span> <span class="sa">f</span><span class="s1">'Contents of directory </span><span class="si">{</span><span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">abspath</span><span class="p">(</span><span class="n">directory</span><span class="p">)</span><span class="si">}</span><span class="s1">'</span>

    <span class="n">msg</span><span class="p">[</span><span class="s1">'To'</span><span class="p">]</span> <span class="o">=</span> <span class="s1">', '</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">args</span><span class="o">.</span><span class="n">recipients</span><span class="p">)</span>

    <span class="n">msg</span><span class="p">[</span><span class="s1">'From'</span><span class="p">]</span> <span class="o">=</span> <span class="n">args</span><span class="o">.</span><span class="n">sender</span>

    <span class="n">msg</span><span class="o">.</span><span class="n">preamble</span> <span class="o">=</span> <span class="s1">'You will not see this in a MIME-aware mail reader.</span><span class="se">\n</span><span class="s1">'</span>

    <span class="k">for</span> <span class="n">filename</span> <span class="ow">in</span> <span class="n">os</span><span class="o">.</span><span class="n">listdir</span><span class="p">(</span><span class="n">directory</span><span class="p">):</span>

    <span class="n">path</span> <span class="o">=</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">directory</span><span class="p">,</span> <span class="n">filename</span><span class="p">)</span>

    <span class="k">if</span> <span class="ow">not</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">isfile</span><span class="p">(</span><span class="n">path</span><span class="p">):</span>

    <span class="k">continue</span>

    <span class="c1"># 根据文件扩展名来猜测内容类型。</span>

    <span class="c1"># 编码格式将被忽略,不过我们应当检查某些简单事务</span>

    <span class="c1"># 例如是否为 gzip 或压缩文件。</span>

    <span class="n">ctype</span><span class="p">,</span> <span class="n">encoding</span> <span class="o">=</span> <span class="n">mimetypes</span><span class="o">.</span><span class="n">guess_file_type</span><span class="p">(</span><span class="n">path</span><span class="p">)</span>

    <span class="k">if</span> <span class="n">ctype</span> <span class="ow">is</span> <span class="kc">None</span> <span class="ow">or</span> <span class="n">encoding</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span><span class="p">:</span>

    <span class="c1"># 不可以猜测,或者文件已被编码(压缩),</span>

    <span class="c1"># 因此我们使用基本的比特位数据类型。</span>

    <span class="n">ctype</span> <span class="o">=</span> <span class="s1">'application/octet-stream'</span>

    <span class="n">maintype</span><span class="p">,</span> <span class="n">subtype</span> <span class="o">=</span> <span class="n">ctype</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s1">''<span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span>

    <span class="k">with</span> <span class="nb">open</span><span class="p">(</span><span class="n">path</span><span class="p">,</span> <span class="s1">'rb'</span><span class="p">)</span> <span class="k">as</span> <span class="n">fp</span><span class="p">:</span>

    <span class="n">msg</span><span class="o">.</span><span class="n">add_attachment</span><span class="p">(</span><span class="n">fp</span><span class="o">.</span><span class="n">read</span><span class="p">(),</span>

    <span class="n">maintype</span><span class="o">=</span><span class="n">maintype</span><span class="p">,</span>

    <span class="n">subtype</span><span class="o">=</span><span class="n">subtype</span><span class="p">,</span>

    <span class="n">filename</span><span class="o">=</span><span class="n">filename</span><span class="p">)</span>

    <span class="c1"># 现在执行消息发送或存储</span>

    <span class="k">if</span> <span class="n">args</span><span class="o">.</span><span class="n">output</span><span class="p">:</span>

    <span class="k">with</span> <span class="nb">open</span><span class="p">(</span><span class="n">args</span><span class="o">.</span><span class="n">output</span><span class="p">,</span> <span class="s1">'wb'</span><span class="p">)</span> <span class="k">as</span> <span class="n">fp</span><span class="p">:</span>

    <span class="n">fp</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="n">msg</span><span class="o">.</span><span class="n">as_bytes</span><span class="p">(</span><span class="n">policy</span><span class="o">=</span><span class="n">SMTP</span><span class="p">))</span>

    <span class="k">else</span><span class="p">:</span>

    <span class="k">with</span> <span class="n">smtplib</span><span class="o">.</span><span class="n">SMTP</span><span class="p">(</span><span class="s1">'localhost'</span><span class="p">)</span> <span class="k">as</span> <span class="n">s</span><span class="p">:</span>

    <span class="n">s</span><span class="o">.</span><span class="n">send_message</span><span class="p">(</span><span class="n">msg</span><span class="p">)</span>

    <span class="k">if</span> <span class="vm">name</span> <span class="o">==</span> <span class="s1">'main'</span><span class="p">:</span>

    <span class="n">main</span><span class="p">()</span>

    <span></span><span class="ch">#!/usr/bin/env python3</span>

    <span class="sd">"""将 MIME 消息解包到一个文件目录中。"""</span>

    <span class="kn">import</span><span class="w"> </span><span class="nn">os</span>

    <span class="kn">import</span><span class="w"> </span><span class="nn">email</span>

    <span class="kn">import</span><span class="w"> </span><span class="nn">mimetypes</span>

    <span class="kn">from</span><span class="w"> </span><span class="nn">email.policy</span><span class="w"> </span><span class="kn">import</span> <span class="n">default</span>

    <span class="kn">from</span><span class="w"> </span><span class="nn">argparse</span><span class="w"> </span><span class="kn">import</span> <span class="n">ArgumentParser</span>

    <span class="k">def</span><span class="w"> </span><span class="nf">main</span><span class="p">():</span>

    <span class="n">parser</span> <span class="o">=</span> <span class="n">ArgumentParser</span><span class="p">(</span><span class="n">description</span><span class="o">=</span><span class="s2">"""</span><span class="se">\</span>

    <span class="s2">Unpack a MIME message into a directory of files.</span>

    <span class="s2">"""</span><span class="p">)</span>

    <span class="n">parser</span><span class="o">.</span><span class="n">add_argument</span><span class="p">(</span><span class="s1">'-d'</span><span class="p">,</span> <span class="s1">'—directory'</span><span class="p">,</span> <span class="n">required</span><span class="o">=</span><span class="kc">True</span><span class="p">,</span>

    <span class="n">help</span><span class="o">=</span><span class="s2">"""Unpack the MIME message into the named</span>

    <span class="s2"> directory, which will be created if it doesn't already</span>

    <span class="s2"> exist."""</span><span class="p">)</span>

    <span class="n">parser</span><span class="o">.</span><span class="n">add_argument</span><span class="p">(</span><span class="s1">'msgfile'</span><span class="p">)</span>

    <span class="n">args</span> <span class="o">=</span> <span class="n">parser</span><span class="o">.</span><span class="n">parse_args</span><span class="p">()</span>

    <span class="k">with</span> <span class="nb">open</span><span class="p">(</span><span class="n">args</span><span class="o">.</span><span class="n">msgfile</span><span class="p">,</span> <span class="s1">'rb'</span><span class="p">)</span> <span class="k">as</span> <span class="n">fp</span><span class="p">:</span>

    <span class="n">msg</span> <span class="o">=</span> <span class="n">email</span><span class="o">.</span><span class="n">message_from_binary_file</span><span class="p">(</span><span class="n">fp</span><span class="p">,</span> <span class="n">policy</span><span class="o">=</span><span class="n">default</span><span class="p">)</span>

    <span class="k">try</span><span class="p">:</span>

    <span class="n">os</span><span class="o">.</span><span class="n">mkdir</span><span class="p">(</span><span class="n">args</span><span class="o">.</span><span class="n">directory</span><span class="p">)</span>

    <span class="k">except</span> <span class="ne">FileExistsError</span><span class="p">:</span>

    <span class="k">pass</span>

    <span class="n">counter</span> <span class="o">=</span> <span class="mi">1</span>

    <span class="k">for</span> <span class="n">part</span> <span class="ow">in</span> <span class="n">msg</span><span class="o">.</span><span class="n">walk</span><span class="p">():</span>

    <span class="c1"># multipart/* 只是一些容器</span>

    <span class="k">if</span> <span class="n">part</span><span class="o">.</span><span class="n">get_content_maintype</span><span class="p">()</span> <span class="o">==</span> <span class="s1">'multipart'</span><span class="p">:</span>

    <span class="k">continue</span>

    <span class="c1"># 应用程序真的应该对所给文件名做无害化处理</span>

    <span class="c1"># 以保证 email 消息不能被用来覆盖重要的文件</span>

    <span class="n">filename</span> <span class="o">=</span> <span class="n">part</span><span class="o">.</span><span class="n">get_filename</span><span class="p">()</span>

    <span class="k">if</span> <span class="ow">not</span> <span class="n">filename</span><span class="p">:</span>

    <span class="n">ext</span> <span class="o">=</span> <span class="n">mimetypes</span><span class="o">.</span><span class="n">guess_extension</span><span class="p">(</span><span class="n">part</span><span class="o">.</span><span class="n">get_content_type</span><span class="p">())</span>

    <span class="k">if</span> <span class="ow">not</span> <span class="n">ext</span><span class="p">:</span>

    <span class="c1"># Use a generic bag-of-bits extension</span>

    <span class="n">ext</span> <span class="o">=</span> <span class="s1">'.bin'</span>

    <span class="n">filename</span> <span class="o">=</span> <span class="sa">f</span><span class="s1">'part-</span><span class="si">{</span><span class="n">counter</span><span class="si">:</span><span class="s1">03d</span><span class="si">}{</span><span class="n">ext</span><span class="si">}</span><span class="s1">'</span>

    <span class="n">counter</span> <span class="o">+=</span> <span class="mi">1</span>

    <span class="k">with</span> <span class="nb">open</span><span class="p">(</span><span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">args</span><span class="o">.</span><span class="n">directory</span><span class="p">,</span> <span class="n">filename</span><span class="p">),</span> <span class="s1">'wb'</span><span class="p">)</span> <span class="k">as</span> <span class="n">fp</span><span class="p">:</span>

    <span class="n">fp</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="n">part</span><span class="o">.</span><span class="n">get_payload</span><span class="p">(</span><span class="n">decode</span><span class="o">=</span><span class="kc">True</span><span class="p">))</span>

    <span class="k">if</span> <span class="vm">name</span> <span class="o">==</span> <span class="s1">'main'</span><span class="p">:</span>

    <span class="n">main</span><span class="p">()</span>

    <span></span><span class="ch">#!/usr/bin/env python3</span>

    <span class="kn">import</span><span class="w"> </span><span class="nn">smtplib</span>

    <span class="kn">from</span><span class="w"> </span><span class="nn">email.message</span><span class="w"> </span><span class="kn">import</span> <span class="n">EmailMessage</span>

    <span class="kn">from</span><span class="w"> </span><span class="nn">email.headerregistry</span><span class="w"> </span><span class="kn">import</span> <span class="n">Address</span>

    <span class="kn">from</span><span class="w"> </span><span class="nn">email.utils</span><span class="w"> </span><span class="kn">import</span> <span class="n">make_msgid</span>

    <span class="c1"># 创建基本的文本消息。</span>

    <span class="n">msg</span> <span class="o">=</span> <span class="n">EmailMessage</span><span class="p">()</span>

    <span class="n">msg</span><span class="p">[</span><span class="s1">'Subject'</span><span class="p">]</span> <span class="o">=</span> <span class="s2">"Pourquoi pas des asperges pour ce midi ?"</span>

    <span class="n">msg</span><span class="p">[</span><span class="s1">'From'</span><span class="p">]</span> <span class="o">=</span> <span class="n">Address</span><span class="p">(</span><span class="s2">"Pepé Le Pew"</span><span class="p">,</span> <span class="s2">"pepe"</span><span class="p">,</span> <span class="s2">"example.com"</span><span class="p">)</span>

    <span class="n">msg</span><span class="p">[</span><span class="s1">'To'</span><span class="p">]</span> <span class="o">=</span> <span class="p">(</span><span class="n">Address</span><span class="p">(</span><span class="s2">"Penelope Pussycat"</span><span class="p">,</span> <span class="s2">"penelope"</span><span class="p">,</span> <span class="s2">"example.com"</span><span class="p">),</span>

    <span class="n">Address</span><span class="p">(</span><span class="s2">"Fabrette Pussycat"</span><span class="p">,</span> <span class="s2">"fabrette"</span><span class="p">,</span> <span class="s2">"example.com"</span><span class="p">))</span>

    <span class="n">msg</span><span class="o">.</span><span class="n">set_content</span><span class="p">(</span><span class="s2">"""</span><span class="se">\</span>

    <span class="s2">Salut!</span>

    <span class="s2">Cette recette [1] sera sûrement un très bon repas.</span>

    <span class="s2">[1] http://www.yummly.com/recipe/Roasted-Asparagus-Epicurious-203718</span&gt;

    <span class="s2">—Pepé</span>

    <span class="s2">"""</span><span class="p">)</span>

    <span class="c1"># 增加 html 版本。 这会将消息转换为一个 multipart/alternative 容器,</span>

    <span class="c1"># 原始文本消息作为第一部分而新的 html 消息作为第二部分。</span>

    <span class="n">asparagus_cid</span> <span class="o">=</span> <span class="n">make_msgid</span><span class="p">()</span>

    <span class="n">msg</span><span class="o">.</span><span class="n">add_alternative</span><span class="p">(</span><span class="s2">"""</span><span class="se">\</span>

    <span class="s2"><html></span>

    <span class="s2"> <head></head></span>

    <span class="s2"> <body></span>

    <span class="s2"> <p>Salut!</p></span>

    <span class="s2"> <p>Cette</span>

    <span class="s2"> <a href="http://www.yummly.com/recipe/Roasted-Asparagus-Epicurious-203718"></span&gt;

    <span class="s2"> recette</span>

    <span class="s2"> </a> sera sûrement un très bon repas.</span>

    <span class="s2"> </p></span>

    <span class="s2"> <img src="cid:</span><span class="si">{asparagus_cid}</span><span class="s2">" ><span>

    <span class="s2"> </body></span>

    <span class="s2"></html></span>

    <span class="s2">"""</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">asparagus_cid</span><span class="o">=</span><span class="n">asparagus_cid</span><span class="p">[</span><span class="mi">1</span><span class="p">:</span><span class="o">-</span><span class="mi">1</span><span class="p">]),</span> <span class="n">subtype</span><span class="o">=</span><span class="s1">'html'</span><span class="p">)</span>

    <span class="c1"># 请注意我们需要将 <> 从 msgid 中去掉以便在 html 中使用。</span>

    <span class="c1"># 现在添加相关图像到 html 部分中。</span>

    <span class="k">with</span> <span class="nb">open</span><span class="p">(</span><span class="s2">"roasted-asparagus.jpg"</span><span class="p">,</span> <span class="s1">'rb'</span><span class="p">)</span> <span class="k">as</span> <span class="n">img</span><span class="p">:</span>

    <span class="n">msg</span><span class="o">.</span><span class="n">get_payload</span><span class="p">()[</span><span class="mi">1</span><span class="p">]</span><span class="o">.</span><span class="n">add_related</span><span class="p">(</span><span class="n">img</span><span class="o">.</span><span class="n">read</span><span class="p">(),</span> <span class="s1">'image'</span><span class="p">,</span> <span class="s1">'jpeg'</span><span class="p">,</span>

    <span class="n">cid</span><span class="o">=</span><span class="n">asparagus_cid</span><span class="p">)</span>

    <span class="c1"># 创建我们将要发送的内容的本地副本。</span>

    <span class="k">with</span> <span class="nb">open</span><span class="p">(</span><span class="s1">'outgoing.msg'</span><span class="p">,</span> <span class="s1">'wb'</span><span class="p">)</span> <span class="k">as</span> <span class="n">f</span><span class="p">:</span>

    <span class="n">f</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="nb">bytes</span><span class="p">(</span><span class="n">msg</span><span class="p">))</span>

    <span class="c1"># 通过本地 SMTP 服务器发送消息。</span>

    <span class="k">with</span> <span class="n">smtplib</span><span class="o">.</span><span class="n">SMTP</span><span class="p">(</span><span class="s1">'localhost'</span><span class="p">)</span> <span class="k">as</span> <span class="n">s</span><span class="p">:</span>

    <span class="n">s</span><span class="o">.</span><span class="n">send_message</span><span class="p">(</span><span class="n">msg</span><span class="p">)</span>

    <span></span><span class="kn">import</span><span class="w"> </span><span class="nn">os</span>

    <span class="kn">import</span><span class="w"> </span><span class="nn">sys</span>

    <span class="kn">import</span><span class="w"> </span><span class="nn">tempfile</span>

    <span class="kn">import</span><span class="w"> </span><span class="nn">mimetypes</span>

    <span class="kn">import</span><span class="w"> </span><span class="nn">webbrowser</span>

    <span class="c1"># 导入我们需要的 email 模块</span>

    <span class="kn">from</span><span class="w"> </span><span class="nn">email</span><span class="w"> </span><span class="kn">import</span> <span class="n">policy</span>

    <span class="kn">from</span><span class="w"> </span><span class="nn">email.parser</span><span class="w"> </span><span class="kn">import</span> <span class="n">BytesParser</span>

    <span class="k">def</span><span class="w"> </span><span class="nf">magic_html_parser</span><span class="p">(</span><span class="n">html_text</span><span class="p">,</span> <span class="n">partfiles</span><span class="p">):</span>

    <span class="w"> </span><span class="sd">"""返回链接到 partfiles 的经安全性处理的 html。</span>

    <span class="sd"> 重写 href="cid:…." 属性以指向 partfiles 中的文件名。</span>

    <span class="sd"> 虽然并非琐碎,这应可使用 html.parser 来实现。</span>

    <span class="sd"> """</span>

    <span class="k">raise</span> <span class="ne">NotImplementedError</span><span class="p">(</span><span class="s2">"Add the magic needed"</span><span class="p">)</span>

    <span class="c1"># 在真正的程序中你将从参数中获得文件名。</span>

    <span class="k">with</span> <span class="nb">open</span><span class="p">(</span><span class="s1">'outgoing.msg'</span><span class="p">,</span> <span class="s1">'rb'</span><span class="p">)</span> <span class="k">as</span> <span class="n">fp</span><span class="p">:</span>

    <span class="n">msg</span> <span class="o">=</span> <span class="n">BytesParser</span><span class="p">(</span><span class="n">policy</span><span class="o">=</span><span class="n">policy</span><span class="o">.</span><span class="n">default</span><span class="p">)</span><span class="o">.</span><span class="n">parse</span><span class="p">(</span><span class="n">fp</span><span class="p">)</span>

    <span class="c1"># 现在可通过字典形式访问标头条目,并且任何非 ASCII 内容</span>

    <span class="c1"># 都将被转换为 unicode:</span>

    <span class="nb">print</span><span class="p">(</span><span class="s1">'To:'</span><span class="p">,</span> <span class="n">msg</span><span class="p">[</span><span class="s1">'to'</span><span class="p">])</span>

    <span class="nb">print</span><span class="p">(</span><span class="s1">'From:'</span><span class="p">,</span> <span class="n">msg</span><span class="p">[</span><span class="s1">'from'</span><span class="p">])</span>

    <span class="nb">print</span><span class="p">(</span><span class="s1">'Subject:'</span><span class="p">,</span> <span class="n">msg</span><span class="p">[</span><span class="s1">'subject'</span><span class="p">])</span>

    <span class="c1"># 如果我们想要打印消息内容的预览,可以提取</span>

    <span class="c1"># 未经格式化的载荷并打印其中前三行。 当然,</span>

    <span class="c1"># 如果消息没有纯文本部分则打印 html 的前三行</span>

    <span class="c1"># 可能是无用的,但这只是个概念性的示例。</span>

    <span class="n">simplest</span> <span class="o">=</span> <span class="n">msg</span><span class="o">.</span><span class="n">get_body</span><span class="p">(</span><span class="n">preferencelist</span><span class="o">=</span><span class="p">(</span><span class="s1">'plain'</span><span class="p">,</span> <span class="s1">'html'</span><span class="p">))</span>

    <span class="nb">print</span><span class="p">()</span>

    <span class="nb">print</span><span class="p">(</span><span class="s1">''</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">simplest</span><span class="o">.</span><span class="n">get_content</span><span class="p">()</span><span class="o">.</span><span class="n">splitlines</span><span class="p">(</span><span class="n">keepends</span><span class="o">=</span><span class="kc">True</span><span class="p">)[:</span><span class="mi">3</span><span class="p">]))</span>

    <span class="n">ans</span> <span class="o">=</span> <span class="nb">input</span><span class="p">(</span><span class="s2">"View full message?"</span><span class="p">)</span>

    <span class="k">if</span> <span class="n">ans</span><span class="o">.</span><span class="n">lower</span><span class="p">()[</span><span class="mi">0</span><span class="p">]</span> <span class="o">==</span> <span class="s1">'n'</span><span class="p">:</span>

    <span class="n">sys</span><span class="o">.</span><span class="n">exit</span><span class="p">()</span>

    <span class="c1"># 我们可以提取最丰富的替代项用于显示:</span>

    <span class="n">richest</span> <span class="o">=</span> <span class="n">msg</span><span class="o">.</span><span class="n">get_body</span><span class="p">()</span>

    <span class="n">partfiles</span> <span class="o">=</span> <span class="p">{}</span>

    <span class="k">if</span> <span class="n">richest</span><span class="p">[</span><span class="s1">'content-type'</span><span class="p">]</span><span class="o">.</span><span class="n">maintype</span> <span class="o">==</span> <span class="s1">'text'</span><span class="p">:</span>

    <span class="k">if</span> <span class="n">richest</span><span class="p">[</span><span class="s1">'content-type'</span><span class="p">]</span><span class="o">.</span><span class="n">subtype</span> <span class="o">==</span> <span class="s1">'plain'</span><span class="p">:</span>

    <span class="k">for</span> <span class="n">line</span> <span class="ow">in</span> <span class="n">richest</span><span class="o">.</span><span class="n">get_content</span><span class="p">()</span><span class="o">.</span><span class="n">splitlines</span><span class="p">():</span>

    <span class="nb">print</span><span class="p">(</span><span class="n">line</span><span class="p">)</span>

    <span class="n">sys</span><span class="o">.</span><span class="n">exit</span><span class="p">()</span>

    <span class="k">elif</span> <span class="n">richest</span><span class="p">[</span><span class="s1">'content-type'</span><span class="p">]</span><span class="o">.</span><span class="n">subtype</span> <span class="o">==</span> <span class="s1">'html'</span><span class="p">:</span>

    <span class="n">body</span> <span class="o">=</span> <span class="n">richest</span>

    <span class="k">else</span><span class="p">:</span>

    <span class="nb">print</span><span class="p">(</span><span class="s2">"Don't know how to display </span><span class="si">{}</span><span class="s2">"</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">richest</span><span class="o">.</span><span class="n">get_content_type</span><span class="p">()))</span>

    <span class="n">sys</span><span class="o">.</span><span class="n">exit</span><span class="p">()</span>

    <span class="k">elif</span> <span class="n">richest</span><span class="p">[</span><span class="s1">'content-type'</span><span class="p">]</span><span class="o">.</span><span class="n">content_type</span> <span class="o">==</span> <span class="s1">'multipart/related'</span><span class="p">:</span>

    <span class="n">body</span> <span class="o">=</span> <span class="n">richest</span><span class="o">.</span><span class="n">get_body</span><span class="p">(</span><span class="n">preferencelist</span><span class="o">=</span><span class="p">(</span><span class="s1">'html'</span><span class="p">))</span>

    <span class="k">for</span> <span class="n">part</span> <span class="ow">in</span> <span class="n">richest</span><span class="o">.</span><span class="n">iter_attachments</span><span class="p">():</span>

    <span class="n">fn</span> <span class="o">=</span> <span class="n">part</span><span class="o">.</span><span class="n">get_filename</span><span class="p">()</span>

    <span class="k">if</span> <span class="n">fn</span><span class="p">:</span>

    <span class="n">extension</span> <span class="o">=</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">splitext</span><span class="p">(</span><span class="n">part</span><span class="o">.</span><span class="n">get_filename</span><span class="p">())[</span><span class="mi">1</span><span class="p">]</span>

    <span class="k">else</span><span class="p">:</span>

    <span class="n">extension</span> <span class="o">=</span> <span class="n">mimetypes</span><span class="o">.</span><span class="n">guess_extension</span><span class="p">(</span><span class="n">part</span><span class="o">.</span><span class="n">get_content_type</span><span class="p">())</span>

    <span class="k">with</span> <span class="n">tempfile</span><span class="o">.</span><span class="n">NamedTemporaryFile</span><span class="p">(</span><span class="n">suffix</span><span class="o">=</span><span class="n">extension</span><span class="p">,</span> <span class="n">delete</span><span class="o">=</span><span class="kc">False</span><span class="p">)</span> <span class="k">as</span> <span class="n">f</span><span class="p">:</span>

    <span class="n">f</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="n">part</span><span class="o">.</span><span class="n">get_content</span><span class="p">())</span>

    <span class="c1"># 再次去除 <> 以将 cid 的 email 形式转为 html 形式。</span>

    <span class="n">partfiles</span><span class="p">[</span><span class="n">part</span><span class="p">[</span><span class="s1">'content-id'</span><span class="p">][</span><span class="mi">1</span><span class="p">:</span><span class="o">-</span><span class="mi">1</span><span class="p">]]</span> <span class="o">=</span> <span class="n">f</span><span class="o">.</span><span class="n">name</span>

    <span class="k">else</span><span class="p">:</span>

    <span class="nb">print</span><span class="p">(</span><span class="s2">"Don't know how to display </span><span class="si">{}</span><span class="s2">"</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">richest</span><span class="o">.</span><span class="n">get_content_type</span><span class="p">()))</span>

    <span class="n">sys</span><span class="o">.</span><span class="n">exit</span><span class="p">()</span>

    <span class="k">with</span> <span class="n">tempfile</span><span class="o">.</span><span class="n">NamedTemporaryFile</span><span class="p">(</span><span class="n">mode</span><span class="o">=</span><span class="s1">'w'</span><span class="p">,</span> <span class="n">delete</span><span class="o">=</span><span class="kc">False</span><span class="p">)</span> <span class="k">as</span> <span class="n">f</span><span class="p">:</span>

    <span class="n">f</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="n">magic_html_parser</span><span class="p">(</span><span class="n">body</span><span class="o">.</span><span class="n">get_content</span><span class="p">(),</span> <span class="n">partfiles</span><span class="p">))</span>

    <span class="n">webbrowser</span><span class="o">.</span><span class="n">open</span><span class="p">(</span><span class="n">f</span><span class="o">.</span><span class="n">name</span><span class="p">)</span>

    <span class="n">os</span><span class="o">.</span><span class="n">remove</span><span class="p">(</span><span class="n">f</span><span class="o">.</span><span class="n">name</span><span class="p">)</span>

    <span class="k">for</span> <span class="n">fn</span> <span class="ow">in</span> <span class="n">partfiles</span><span class="o">.</span><span class="n">values</span><span class="p">():</span>

    <span class="n">os</span><span class="o">.</span><span class="n">remove</span><span class="p">(</span><span class="n">fn</span><span class="p">)</span>

    <span class="c1"># 当然,许多 email 消息都有可能破坏这个简单的程序,</span>

    <span class="c1"># 但它将能处理最普通的消息。</span>

    <span></span>To: Penelope Pussycat <penelope@example.com>, Fabrette Pussycat <fabrette@example.com>

    From: Pepé Le Pew <pepe@example.com>

    Subject: Pourquoi pas des asperges pour ce midi ?

    Salut!

    Cette recette [1] sera sûrement un très bon repas.

    备注

    [1] 感谢 Matthew Dixon Cowles 提供最初的灵感和示例。