joe di castrohttp://joedicastro.comSun, 08 May 2011 13:29:00 +0200Enviar un correo electrónico con Pythonhttp://joedicastro.com/enviar-un-correo-electronico-con-python.html<p>Existen varias maneras de enviar un correo electrónico a través de <strong>Python</strong>, por ejemplo empleando el modulo <code>smtplib</code> de la librería estándar de Python. Si estamos en <strong>Linux</strong> y contamos con un servidor de correo funcionando, enviar un correo puede ser algo tan sencillo como este script:</p> <div class="codehilite"><pre><span class="c">#!/usr/bin/env python</span> <span class="c"># -*- coding: utf8 -*-</span> <span class="kn">import</span> <span class="nn">os</span> <span class="kn">import</span> <span class="nn">socket</span> <span class="kn">import</span> <span class="nn">smtplib</span> <span class="k">def</span> <span class="nf">send_mail_local</span><span class="p">(</span><span class="n">subject</span><span class="p">,</span> <span class="n">text</span><span class="p">):</span> <span class="sd">&quot;&quot;&quot;Send a mail to the user&#39;s local mailbox.&quot;&quot;&quot;</span> <span class="c"># Set the local mail address for the script&#39; user</span> <span class="n">email</span> <span class="o">=</span> <span class="s">&quot;@&quot;</span><span class="o">.</span><span class="n">join</span><span class="p">([</span><span class="n">os</span><span class="o">.</span><span class="n">getenv</span><span class="p">(</span><span class="s">&quot;LOGNAME&quot;</span><span class="p">),</span> <span class="n">socket</span><span class="o">.</span><span class="n">gethostname</span><span class="p">()])</span> <span class="n">msg</span> <span class="o">=</span> <span class="p">(</span><span class="s">&quot;From: {0}</span><span class="se">\n</span><span class="s">To: {0}</span><span class="se">\n</span><span class="s">Subject: {1}</span><span class="se">\n</span><span class="s">{2}&quot;</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">email</span><span class="p">,</span> <span class="n">subject</span><span class="p">,</span> <span class="n">text</span><span class="p">))</span> <span class="n">server</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="s">&quot;localhost&quot;</span><span class="p">)</span> <span class="n">server</span><span class="o">.</span><span class="n">sendmail</span><span class="p">(</span><span class="n">email</span><span class="p">,</span> <span class="n">email</span><span class="p">,</span> <span class="n">msg</span><span class="p">)</span> <span class="n">server</span><span class="o">.</span><span class="n">quit</span><span class="p">()</span> <span class="k">return</span> <span class="k">def</span> <span class="nf">main</span><span class="p">():</span> <span class="sd">&quot;&quot;&quot;Main section&quot;&quot;&quot;</span> <span class="n">send_mail_local</span><span class="p">(</span><span class="s">&quot;Comprobando el envío de correo localmente&quot;</span><span class="p">,</span> <span class="s">&quot;Si puedes leer esto, tu servidor local SMTP está OK&quot;</span><span class="p">)</span> <span class="k">print</span><span class="p">(</span><span class="s">&quot;Comprueba el correo en tu buzón local {0}</span><span class="se">\n</span><span class="s">Este normalmente se &quot;</span> <span class="s">&quot;encuentra situado en /var/mail/{1}&quot;</span><span class="o">.</span> <span class="n">format</span><span class="p">(</span><span class="s">&quot;@&quot;</span><span class="o">.</span><span class="n">join</span><span class="p">([</span><span class="n">os</span><span class="o">.</span><span class="n">getenv</span><span class="p">(</span><span class="s">&quot;LOGNAME&quot;</span><span class="p">),</span> <span class="n">socket</span><span class="o">.</span><span class="n">gethostname</span><span class="p">()]),</span> <span class="n">os</span><span class="o">.</span><span class="n">getenv</span><span class="p">(</span><span class="s">&quot;LOGNAME&quot;</span><span class="p">)))</span> <span class="k">if</span> <span class="n">__name__</span> <span class="o">==</span> <span class="s">&quot;__main__&quot;</span><span class="p">:</span> <span class="n">main</span><span class="p">()</span> </pre></div> <p>Que si lo ejecutamos, nos generará una salida por consola como esta:</p> <div class="codehilite"><pre>Comprueba el correo en tu buzón local tuusuario@tumaquina Este normalmente se encuentra situado en /var/mail/tuusuario </pre></div> <p>Y tendrás en la bandeja de correo de tu usuario en la maquina algo como esto:</p> <div class="codehilite"><pre>De: tuusuario@tumaquina Para: tuusuario@tumaquina Asunto: Comprobando el envío de correo localmente Fecha: Sun, 08 May 2011 12:57:30 +0200 Si puedes leer esto, tu servidor local SMTP está OK </pre></div> <p>Es algo realmente sencillo, y la mayoría de las lineas sirven para construir el ejemplo, lo que realmente hace el trabajo, y solo necesita el modulo <code>smtplib</code> para funcionar es esto:</p> <div class="codehilite"><pre><span class="n">server</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="s">&quot;localhost&quot;</span><span class="p">)</span> <span class="n">server</span><span class="o">.</span><span class="n">sendmail</span><span class="p">(</span><span class="n">email</span><span class="p">,</span> <span class="n">email</span><span class="p">,</span> <span class="n">msg</span><span class="p">)</span> <span class="n">server</span><span class="o">.</span><span class="n">quit</span><span class="p">()</span> </pre></div> <p>Pero si lo que queremos es enviar correos más complejos, con adjuntos, empleando servidores SMTP externos y enviar con copia (CC) ó copia oculta (CCO) a varios usuarios, entonces ya necesitamos emplear las opciones del modulo <code>email</code> que nos permite hacer prácticamente cualquier tarea relacionada con los correos electronicos. Para estas situaciones desarrolle en su día una función que ha cubierto todas las situaciones que se me han dado hasta ahora. Además devuelve mensajes de error allí donde algo puede ir mal.</p> <div class="codehilite"><pre><span class="c"># The more complete solution. This adds the Cc: (Carbon Copy) and Bcc: (Blind </span> <span class="c"># Carbon Copy) fields and the ability to add attachments. </span> <span class="k">def</span> <span class="nf">send_email</span><span class="p">(</span><span class="n">subject</span><span class="p">,</span> <span class="n">text</span><span class="p">,</span> <span class="n">send_from</span><span class="o">=</span><span class="s">&quot;&quot;</span><span class="p">,</span> <span class="n">dest_to</span><span class="o">=</span><span class="bp">None</span><span class="p">,</span> <span class="n">attachments</span><span class="o">=</span><span class="bp">None</span><span class="p">,</span> <span class="n">send_cc</span><span class="o">=</span><span class="bp">None</span><span class="p">,</span> <span class="n">send_bcc</span><span class="o">=</span><span class="bp">None</span><span class="p">,</span> <span class="n">server</span><span class="o">=</span><span class="s">&quot;localhost&quot;</span><span class="p">,</span> <span class="n">port</span><span class="o">=</span><span class="mi">25</span><span class="p">,</span> <span class="n">user</span><span class="o">=</span><span class="s">&quot;&quot;</span><span class="p">,</span> <span class="n">passwd</span><span class="o">=</span><span class="s">&quot;&quot;</span><span class="p">):</span> <span class="sd">&quot;&quot;&quot;Send a email with(out) attachment(s) enabling CC and BCC fields.</span> <span class="sd"> Arguments:</span> <span class="sd"> (str) subject -- the mail&#39;s subject</span> <span class="sd"> (str) text -- the message&#39;s text</span> <span class="sd"> (str) send_from -- a sender&#39;s email address (default &quot;&quot;)</span> <span class="sd"> (list) dest_to -- a list of receivers&#39; email addresses (&quot;&quot;)</span> <span class="sd"> (list) attachments -- a list of attachments files (default None)</span> <span class="sd"> (list) send_cc -- a list of carbon copy&#39;s email addresses (def. None)</span> <span class="sd"> (list) send_bcc -- a list of blind carbon copy&#39;s email addresses (None)</span> <span class="sd"> (str) server -- the smtp server (default &quot;localhost&quot;)</span> <span class="sd"> (int) port -- the smtp server port (default 25)</span> <span class="sd"> (str) user -- the smtp server user (default &quot;&quot;)</span> <span class="sd"> (str) passwd --the smtp server password (default &quot;&quot;)</span> <span class="sd"> If &quot;send_from&quot; or &quot;dest_to&quot; are empty or None, then script user&#39;s mailbox </span> <span class="sd"> is assumed instead. Useful for logging scripts</span> <span class="sd"> &quot;&quot;&quot;</span> <span class="n">local_email</span> <span class="o">=</span> <span class="s">&quot;@&quot;</span><span class="o">.</span><span class="n">join</span><span class="p">([</span><span class="n">os</span><span class="o">.</span><span class="n">getenv</span><span class="p">(</span><span class="s">&quot;LOGNAME&quot;</span><span class="p">),</span> <span class="n">socket</span><span class="o">.</span><span class="n">gethostname</span><span class="p">()])</span> <span class="n">send_from</span> <span class="o">=</span> <span class="n">send_from</span> <span class="k">if</span> <span class="n">send_from</span> <span class="k">else</span> <span class="n">local_email</span> <span class="n">dest_to</span> <span class="o">=</span> <span class="n">dest_to</span> <span class="k">if</span> <span class="n">dest_to</span> <span class="k">else</span> <span class="p">[</span><span class="n">local_email</span><span class="p">]</span> <span class="n">dest_to_addrs</span> <span class="o">=</span> <span class="n">dest_to</span> <span class="c"># receivers mails including to, cc and bcc fields</span> <span class="n">message</span> <span class="o">=</span> <span class="n">MIMEMultipart</span><span class="p">()</span> <span class="n">message</span><span class="p">[</span><span class="s">&quot;Subject&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">subject</span> <span class="n">message</span><span class="p">[</span><span class="s">&quot;From&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">send_from</span> <span class="n">message</span><span class="p">[</span><span class="s">&quot;To&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">COMMASPACE</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">dest_to</span><span class="p">)</span> <span class="k">if</span> <span class="n">send_cc</span><span class="p">:</span> <span class="n">message</span><span class="p">[</span><span class="s">&quot;Cc&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">COMMASPACE</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">send_cc</span><span class="p">)</span> <span class="n">dest_to_addrs</span> <span class="o">+=</span> <span class="n">send_cc</span> <span class="k">if</span> <span class="n">send_bcc</span><span class="p">:</span> <span class="n">dest_to_addrs</span> <span class="o">+=</span> <span class="n">send_bcc</span> <span class="n">message</span><span class="p">[</span><span class="s">&quot;Date&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">formatdate</span><span class="p">(</span><span class="n">localtime</span><span class="o">=</span><span class="bp">True</span><span class="p">)</span> <span class="n">message</span><span class="o">.</span><span class="n">preamble</span> <span class="o">=</span> <span class="s">&quot;You&#39;ll not see this in a MIME-aware mail reader.</span><span class="se">\n</span><span class="s">&quot;</span> <span class="n">message</span><span class="o">.</span><span class="n">attach</span><span class="p">(</span><span class="n">MIMEText</span><span class="p">(</span><span class="n">text</span><span class="p">))</span> <span class="c"># For all type of attachments</span> <span class="k">if</span> <span class="n">attachments</span><span class="p">:</span> <span class="k">for</span> <span class="n">att_file</span> <span class="ow">in</span> <span class="n">attachments</span><span class="p">:</span> <span class="k">with</span> <span class="nb">open</span><span class="p">(</span><span class="n">att_file</span><span class="p">,</span> <span class="s">&quot;rb&quot;</span><span class="p">)</span> <span class="k">as</span> <span class="n">attmnt</span><span class="p">:</span> <span class="n">att</span> <span class="o">=</span> <span class="n">MIMEBase</span><span class="p">(</span><span class="s">&quot;application&quot;</span><span class="p">,</span> <span class="s">&quot;octet-stream&quot;</span><span class="p">)</span> <span class="n">att</span><span class="o">.</span><span class="n">set_payload</span><span class="p">(</span><span class="n">attmnt</span><span class="o">.</span><span class="n">read</span><span class="p">())</span> <span class="n">encoders</span><span class="o">.</span><span class="n">encode_base64</span><span class="p">(</span><span class="n">att</span><span class="p">)</span> <span class="n">att</span><span class="o">.</span><span class="n">add_header</span><span class="p">(</span><span class="s">&quot;content-disposition&quot;</span><span class="p">,</span> <span class="s">&quot;attachment&quot;</span><span class="p">,</span> <span class="n">filename</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">basename</span><span class="p">(</span><span class="n">att_file</span><span class="p">))</span> <span class="n">message</span><span class="o">.</span><span class="n">attach</span><span class="p">(</span><span class="n">att</span><span class="p">)</span> <span class="c"># initialize the mail server</span> <span class="n">smtp_server</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="c"># Connect to mail server</span> <span class="k">try</span><span class="p">:</span> <span class="n">smtp_server</span><span class="o">.</span><span class="n">connect</span><span class="p">(</span><span class="n">server</span><span class="p">,</span> <span class="n">port</span><span class="p">)</span> <span class="k">except</span> <span class="n">socket</span><span class="o">.</span><span class="n">gaierror</span><span class="p">:</span> <span class="k">print</span><span class="p">(</span><span class="s">&quot;mail error&quot;</span><span class="p">,</span> <span class="s">&quot;Wrong server, are you sure is correct?&quot;</span><span class="p">)</span> <span class="k">except</span> <span class="n">socket</span><span class="o">.</span><span class="n">error</span><span class="p">:</span> <span class="k">print</span><span class="p">(</span><span class="s">&quot;mail error&quot;</span><span class="p">,</span> <span class="s">&quot;Server unavailable or connection refused&quot;</span><span class="p">)</span> <span class="c"># Login in mail server</span> <span class="k">if</span> <span class="n">server</span> <span class="o">!=</span> <span class="s">&quot;localhost&quot;</span><span class="p">:</span> <span class="k">try</span><span class="p">:</span> <span class="n">smtp_server</span><span class="o">.</span><span class="n">login</span><span class="p">(</span><span class="n">user</span><span class="p">,</span> <span class="n">passwd</span><span class="p">)</span> <span class="k">except</span> <span class="n">smtplib</span><span class="o">.</span><span class="n">SMTPAuthenticationError</span><span class="p">:</span> <span class="k">print</span><span class="p">(</span><span class="s">&quot;mail error&quot;</span><span class="p">,</span> <span class="s">&quot;Authentication error&quot;</span><span class="p">)</span> <span class="k">except</span> <span class="n">smtplib</span><span class="o">.</span><span class="n">SMTPException</span><span class="p">:</span> <span class="k">print</span><span class="p">(</span><span class="s">&quot;mail error&quot;</span><span class="p">,</span> <span class="s">&quot;No suitable authentication method&quot;</span><span class="p">)</span> <span class="c"># Send mail</span> <span class="k">try</span><span class="p">:</span> <span class="n">smtp_server</span><span class="o">.</span><span class="n">sendmail</span><span class="p">(</span><span class="n">send_from</span><span class="p">,</span> <span class="n">dest_to_addrs</span><span class="p">,</span> <span class="n">message</span><span class="o">.</span><span class="n">as_string</span><span class="p">())</span> <span class="k">except</span> <span class="n">smtplib</span><span class="o">.</span><span class="n">SMTPRecipientsRefused</span><span class="p">:</span> <span class="k">print</span><span class="p">(</span><span class="s">&quot;mail error&quot;</span><span class="p">,</span> <span class="s">&quot;All recipients were refused.&quot;</span> <span class="s">&quot;Nobody got the mail.&quot;</span><span class="p">)</span> <span class="k">except</span> <span class="n">smtplib</span><span class="o">.</span><span class="n">SMTPSenderRefused</span><span class="p">:</span> <span class="k">print</span><span class="p">(</span><span class="s">&quot;mail error&quot;</span><span class="p">,</span> <span class="s">&quot;The server didn’t accept the from_addr&quot;</span><span class="p">)</span> <span class="k">except</span> <span class="n">smtplib</span><span class="o">.</span><span class="n">SMTPDataError</span><span class="p">:</span> <span class="k">print</span><span class="p">(</span><span class="s">&quot;mail error&quot;</span><span class="p">,</span> <span class="s">&quot;An unexpected error code, Data refused&quot;</span><span class="p">)</span> <span class="c"># Disconnect from server</span> <span class="n">smtp_server</span><span class="o">.</span><span class="n">quit</span><span class="p">()</span> </pre></div> <p>Para las situaciones en las que no disponemos de un servidor de correo SMTP funcionando, podemos montar uno temporalmente para realizar pruebas. La tarea puede tan sencilla como recurrir a uno de los <strong>python one-liners</strong> que mencionaba en <a href="http://joedicastro.com/python_one_liners_potencia_en_una_sola_linea">Python one-liners. Potencia en una sola línea</a>.</p> <div class="codehilite"><pre><span class="n">python</span> <span class="o">-</span><span class="n">m</span> <span class="n">smtpd</span> <span class="o">-</span><span class="n">n</span> <span class="o">-</span><span class="n">c</span> <span class="n">DebuggingServer</span> <span class="n">localhost</span><span class="p">:</span><span class="mi">8025</span> </pre></div> <p>que es exactamente lo mismo que hace este script que empleo habitualmente para las mismas funciones (me permite montar un segundo servidor SMTP en un puerto distinto sin necesitar permisos de administrador, lo que me permite llamarlo desde otros scripts). Emplear una u otra forma, pues ya depende de uno.</p> <div class="codehilite"><pre><span class="c">#!/usr/bin/env python</span> <span class="c"># -*- coding: utf8 -*-</span> <span class="kn">import</span> <span class="nn">smtpd</span> <span class="kn">import</span> <span class="nn">asyncore</span> <span class="k">def</span> <span class="nf">smtp_server</span><span class="p">(</span><span class="n">port</span><span class="p">):</span> <span class="sd">&quot;&quot;&quot;Starts a smtp server for test purposes.&quot;&quot;&quot;</span> <span class="n">smtpd</span><span class="o">.</span><span class="n">DebuggingServer</span><span class="p">((</span><span class="s">&quot;localhost&quot;</span><span class="p">,</span> <span class="n">port</span><span class="p">),</span> <span class="bp">None</span><span class="p">)</span> <span class="n">smtp_server</span><span class="p">(</span><span class="mi">8025</span><span class="p">)</span> <span class="k">try</span><span class="p">:</span> <span class="n">asyncore</span><span class="o">.</span><span class="n">loop</span><span class="p">()</span> <span class="k">except</span> <span class="ne">KeyboardInterrupt</span><span class="p">:</span> <span class="k">pass</span> </pre></div> <p>El código completo con ejemplos de estas funciones, se puede encontrar en mi repositorio <em>Python Recipes</em> que se encuentra alojado en <a href="http://github.com/joedicastro/python-recipes">github</a>.</p>joe di castroSun, 08 May 2011 13:29:00 +0200http://joedicastro.com/enviar-un-correo-electronico-con-python.htmlpythonemailsmtplinuxone-liner