Usa Python para crear y enviar archivos de Excel automáticamente

Python cuenta con una amplia gama de posibilidades a la hora de trabajar, y el día de hoy toca aprender a enviar archivos Excel usando el propio Outlook.

Este ejemplo hace un buen trabajo en automatizar un proceso altamente manual en donde alguien hubiera tenido que hacer mucho trabajo de copiar y pegar en archivos manipulados manualmente. Con esta solución se espera poder ayudarte a automatizar algunas de esas partes tediosas de tu trabajo.

Preparando el codigo de Python

El primer paso para resolver el problema es poner los imports en su lugar:

import datetime
import shutil
import pandas as pd
import win32com.client as win32

Ahora acomodaremos algunas secuencias con la fecha actual y nuestra estructura de directorios:

##Set Date Formats
 today_string = datetime.datetime.today().strftime('%m%d%Y_%I%p')
 today_string2 = datetime.datetime.today().strftime('%b %d, %Y')

##Set Folder Targets for Attachments and Archiving
 attachment_path = Path.cwd() / 'data' / 'attachments'
 archive_dir = Path.cwd() / 'archive'
 src_file = Path.cwd() / 'data' / 'Example4.xlsx'

Ahora veamos el archivo de datos que necesitamos procesar:

df = pd.read_excel(src_file)
 df.head()

Creando los archivos a enviar

El siguiente paso es agrupar todas las transacciones CUSTOMER_ID juntas. Empezaremos por usar groupby en CUSTOMER_ID.

customer_group = df.groupby('Customer_Key')

En este caso, puede que no sea obvio lo que customer_group hace. Un loop nos muestra cómo podemos procesar este objeto agrupado:

for ID, group_df in customer_group:
     print(ID)
0 
1
2

Y aquí está el último group_df que nos muestra todas las transacciones para el cliente A1005:

Con esto tenemos todo lo necesario para crear un archivo de Excel para cada cliente y guardarlo en un directorio para usos futuros:

##Write each ID, Group to Individual Excel files and use ID to name each file with Today's Date
 attachments = []
 for ID, group_df in customer_group:
     attachment = attachment_path / f'{ID}_{today_string}.xlsx'
     group_df.to_excel(attachment, index=False)
     attachments.append((ID, str(attachment)))

La lista de attachments contiene la ID del cliente y la ruta completa al archivo:

[('0',
 'D:\aplan\Documents\ENTRADAS\datos\attach\0_01162021_12PM.xlsx'),
 ('1',
 'D:\aplan\Documents\ENTRADAS\datos\attach\1_01162021_12PM.xlsx'),
 ('2',
 'D:\aplan\Documents\ENTRADAS\datos\attach\2_01162021_12PM.xlsx')]

Para hacer el procesamiento más fácil, convertiremos la lista a un DataFrame:

df2 = pd.DataFrame(attachments, columns=['Customer_Key', 'FILE'])

Enviando los correos

La parte final para preparar nuestros datos es generar una lista de archivos con sus direcciones de correo, la cual haremos al combinar los DataFrames:

email_merge = pd.merge(df, df2, how='left')
combined = email_merge[['Customer_Key', 'Email', 'FILE']].drop_duplicates()

Lo cual nos dará este simple DataFrame:

Python enviar archivos Excel 1

Con esto ya hemos juntado la lista de clientes, sus correos y los archivos adjuntos. Ahora necesitamos enviar un correo con Outlook, para lo cual necesitaremos este código:

##Email Individual Reports to Respective Recipients
class EmailsSender:
     def init(self):
         self.outlook = win32.Dispatch('outlook.application')
     def send_email(self, to_email_address, attachment_path):     
         mail = self.outlook.CreateItem(0)
         mail.To = to_email_address
         mail.Subject = today_string2 + ' Report'
         mail.Body = """Please find today's report attached."""
         mail.Attachments.Add(Source=attachment_path)
         # Use this to show the email
         #mail.Display(True)
         # Uncomment to send
         #mail.Send()

Podemos usar esta simple clase para generar los emails y adjuntar el archivo de Excel.

email_sender = EmailsSender()
 for index, row in combined.iterrows():
     email_sender.send_email(row['EMAIL'], row['FILE'])

El paso final será mover los archivos a nuestro directorio de archivo:

##Move the files to the archive location
 for f in attachments:
     shutil.move(f[1], archive_dir)

Aun si es un proceso que no requiere más de una hora como enviar archivos de Excel, podemos usarlo como punto de inicio para ir aprendiendo a usar Python para hacer las cosas más fáciles. Aquí te dejo el código completo para que lo veas.

import datetime
import shutil
import pandas as pd
import win32com.client as win32
Email Individual Reports to Respective Recipients

class EmailsSender:
      def init(self):
          self.outlook = win32.Dispatch('outlook.application')
      def send_email(self, to_email_address, attachment_path):     
          mail = self.outlook.CreateItem(0)
          mail.To = to_email_address
          mail.Subject = today_string2 + ' Report'
          mail.Body = """Please find today's report attached."""
          mail.Attachments.Add(Source=attachment_path)
          # Use this to show the email
          #mail.Display(True)
          # Uncomment to send
          #mail.Send()

## Set Date Formats
today_string = datetime.datetime.today().strftime('%m%d%Y_%I%p')
today_string2 = datetime.datetime.today().strftime('%b %d, %Y')
## Set Folder Targets for Attachments and Archiving
attachment_path = 'D:/aplan/Documents/ENTRADAS/datos/attach'
archive_dir = 'D:/aplan/Documents/ENTRADAS/datos/archivo'
src_file = 'D:/aplan/Documents/ENTRADAS/datos/Archivos_enviar.xlsx'

df = pd.read_excel(src_file)
df.head()

customer_group = df.groupby('Customer Key')
for ID, group_df in customer_group:
     print(ID)

## Write each ID, Group to Individual Excel files and use ID to name each file with Today's Date
attachments = []
for ID, group_df in customer_group:
     attachment = attachment_path + '/' + f'{ID}_{today_string}.xlsx'
     group_df.to_excel(attachment, index=False)
     attachments.append((ID, str(attachment)))

df2 = pd.DataFrame(attachments, columns=['Customer Key', 'FILE'])
email_merge = pd.merge(df, df2, how='left')
combined = email_merge[['Customer Key', 'Email', 'FILE']].drop_duplicates()

email_sender = EmailsSender()
for index, row in combined.iterrows():
     email_sender.send_email(row['EMAIL'], row['FILE'])

## Move the files to the archive location
for f in attachments:
     shutil.move(f[1], archive_dir)

Aunque aun no lo parezca, los casos en donde unas cuantas líneas de código Python solucionan verdaderos problemas empresariales que ahorran grandes cantidades de tiempo y dinero a organizaciones son reales e impresionantes. Una de las partes que hacen a estos ejemplos tan difíciles de creer es cuando son logrados sin necesidad de alguna capacitación formal en programación.

Cualquier duda nos leemos abajo.

Usa Python para crear y enviar archivos de Excel automáticamente
Scroll hacia arriba