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:
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.