지난번에 이메일을 엑셀파일로 만드는 프로그램을 작성했습니다. 메일을 엑셀로 관리한다면 해당 엑셀파일에서 메일을 추출해 특정내용을 자동으로 이메일 발송하는 프로그램을 만들면 유용하겠죠? 그럼 이번에는 어떤 형태의 프로그램으로 자동발송할지 진행해 보겠습니다.
우선 기초적인 단계로 한다면
"엑셀파일을 읽어서 어떤내용의 이메일을 전체발송해 줘"라고 chatGPT에게 말하면 간단하게 프로그램은 완성되겠죠? 하지만 이제 경험이 쌓였으니 우리는 좀 더 구체적인 프로그램을 생각해 구현해 달라고 해봅시다. 전적으로 제 개인적으로 편할 거 같은 프로그램인 것이니 여러분도 여러분 나름대로 편리하겠다 생각되는 기능을 넣어서 구현하시면 됩니다.
프롬프트
엑셀에 정리되어있는 이메일을 읽어서 이메일을 자동으로 발송하고 싶은데 이걸 GUI 가 있는 파이썬 프로그램으로 작성하고 싶어 엑셀파일을 선택하는것과 이메일 내용작성하는란 그리고 일괄로 발송하는 버튼이 있는게 좋겠어 엑셀파일을 선택했을때 이메일 갯수와 선택된 이메일 리스트를 체크박스 형태로 20개씩 보여주고 스크롤처리하면 다수의 이메일도 확인할 수 있을거같아. 최종발송은 체크된 이메일에게만 발송하는 형식이면 좋겠어
ChatGPT 결과
좋은 아이디어네요! 이 프로그램은 다음과 같은 기능을 포함해야 할 것 같습니다:
- 엑셀 파일 선택: 사용자가 이메일 목록이 담긴 엑셀 파일을 선택하도록 합니다.
- 이메일 리스트 표시: 엑셀 파일에서 읽어온 이메일을 체크박스 형태로 20개씩 보여주고, 사용자가 체크할 수 있게 합니다.
- 이메일 내용 작성: 이메일 내용을 작성할 수 있는 텍스트 박스가 있어야 합니다.
- 이메일 발송 버튼: 사용자가 선택한 이메일에만 이메일을 발송할 수 있도록 하는 버튼을 제공합니다.
- 스크롤 처리: 이메일 리스트가 길어지면 스크롤을 통해 20개씩 보여주도록 합니다.
이를 위해 사용될 주요 라이브러리는 다음과 같습니다:
- tkinter: GUI를 만들기 위한 라이브러리입니다.
- pandas: 엑셀 파일을 읽고 데이터를 처리하는 데 사용됩니다.
- smtplib: 이메일을 발송하는 데 사용됩니다.
- openpyxl: 엑셀 파일을 읽는 데 사용됩니다.
설명
- 엑셀 파일 열기 (open_file): filedialog.askopenfilename을 사용하여 엑셀 파일을 선택하고, 선택된 파일을 pandas로 읽어 이메일 리스트를 가져옵니다. 이메일은 체크박스 형태로 20개씩 화면에 표시됩니다.
- 이메일 발송 (send_email): 선택된 이메일에만 이메일을 발송하는 함수입니다. SMTP 서버를 통해 이메일을 전송합니다. Gmail을 사용하는 예시로 설정했지만 다른 이메일 서버를 사용할 수도 있습니다.
- GUI (tkinter): tkinter를 사용하여 간단한 GUI를 만듭니다. 이메일 제목과 내용을 입력할 수 있는 영역, 엑셀 파일을 열기 위한 버튼, 이메일 발송 버튼이 있습니다.
- 스크롤 처리: 이메일 리스트가 길어지면, tkinter의 Canvas와 Scrollbar를 추가하여 이메일 리스트를 스크롤할 수 있게 처리할 수 있습니다. (이 부분은 추가적으로 구현이 필요합니다.)
이 코드로 기본적인 이메일 발송 프로그램을 만들 수 있으며, 엑셀 파일에서 이메일을 읽고, 사용자가 선택한 이메일에만 발송할 수 있습니다. 추가적으로 에러 처리나 SMTP 서버 설정을 자신에게 맞게 수정하시면 됩니다.
소스
import tkinter as tk
from tkinter import filedialog, messagebox
import pandas as pd
import smtplib
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
# 이메일 발송 함수
def send_email(subject, body, recipients):
try:
# SMTP 서버 설정 (예: Gmail)
server = smtplib.SMTP('smtp.gmail.com', 587)
server.starttls()
server.login('your_email@gmail.com', 'your_password')
# 이메일 발송
for email in recipients:
msg = MIMEMultipart()
msg['From'] = 'your_email@gmail.com'
msg['To'] = email
msg['Subject'] = subject
msg.attach(MIMEText(body, 'plain'))
server.sendmail(msg['From'], msg['To'], msg.as_string())
server.quit()
messagebox.showinfo("성공", "이메일이 성공적으로 발송되었습니다.")
except Exception as e:
messagebox.showerror("오류", f"이메일 발송 중 오류가 발생했습니다: {e}")
# 엑셀 파일 열기 함수
def open_file():
file_path = filedialog.askopenfilename(filetypes=[("Excel files", "*.xlsx")])
if file_path:
try:
# 엑셀 파일 읽기
df = pd.read_excel(file_path)
emails = df['Email'].dropna().tolist() # 'Email' 열에서 이메일 리스트 가져오기
# 이메일 리스트 표시
for widget in email_list_frame.winfo_children():
widget.destroy()
for i, email in enumerate(emails[:20]): # 첫 20개 이메일만 표시
checkbox = tk.Checkbutton(email_list_frame, text=email, variable=email_vars[i])
checkbox.grid(row=i, column=0, sticky="w")
email_vars.clear()
for i in range(20):
email_vars.append(tk.BooleanVar())
email_list_frame.update_idletasks()
messagebox.showinfo("파일 열기 성공", f"{len(emails)}개의 이메일을 찾았습니다.")
except Exception as e:
messagebox.showerror("오류", f"엑셀 파일을 읽는 중 오류가 발생했습니다: {e}")
# 이메일 발송 함수 (선택된 이메일에만 발송)
def send_selected_emails():
subject = subject_entry.get()
body = body_text.get("1.0", tk.END)
# 선택된 이메일 리스트 가져오기
recipients = []
for i, var in enumerate(email_vars):
if var.get():
recipients.append(emails[i])
if recipients:
send_email(subject, body, recipients)
else:
messagebox.showwarning("선택 오류", "보낼 이메일을 선택해 주세요.")
# GUI 설정
root = tk.Tk()
root.title("이메일 발송기")
# 이메일 내용 작성
subject_label = tk.Label(root, text="이메일 제목")
subject_label.pack()
subject_entry = tk.Entry(root, width=50)
subject_entry.pack()
body_label = tk.Label(root, text="이메일 내용")
body_label.pack()
body_text = tk.Text(root, width=50, height=10)
body_text.pack()
# 이메일 리스트 표시
email_list_frame = tk.Frame(root)
email_list_frame.pack()
email_vars = []
emails = []
# 엑셀 파일 열기 버튼
open_button = tk.Button(root, text="엑셀 파일 열기", command=open_file)
open_button.pack()
# 발송 버튼
send_button = tk.Button(root, text="선택된 이메일 발송", command=send_selected_emails)
send_button.pack()
# 실행
root.mainloop()
결과
테스트용 이메일을 제 계정 두개정도에 추가해 봤습니다.
역시 엑셀형식에서 제대로 불러오지 못하고 있습니다. 이제 원인을 찾아보겠습니다.
중간에 컴퓨터가 꺼져서 chatGPT 로그인 후 다시 소스를 보여주고 진행하기로 했습니다.
자동으로 소스를 검증하더니 자체 수정에 들어갑니다.
chatGPT 소스검증
✅ 개선할 점
- 보안 문제 (이메일 & 비밀번호 하드코딩)
- your_email@gmail.com, your_password 하드코딩 ❌
- 환경 변수 또는 .env 파일 사용 ✅
- 엑셀 데이터 처리 오류
- emails 리스트가 open_file 함수 내부에서만 갱신됨 → send_selected_emails에서 접근 불가능
- 전역 변수로 emails를 업데이트하는 로직 수정 필요
- SMTP 서버 연결 최적화
- server.sendmail() 호출 후 server.quit() 실행되는데, 대량 이메일 전송 시 효율적이지 않음
- with smtplib.SMTP(...) 사용하면 자동으로 연결 해제
- GUI 체크박스 관련 문제
- email_vars가 open_file() 호출 시 재초기화 안 되어 체크박스 동기화 문제 발생 가능
- GUI 개선 (스크롤 추가)
- 이메일 리스트가 많으면 한 화면에서 보기 어려움 → Scrollbar 추가
- 예외 처리 강화
- 이메일 전송 실패 시 개별 이메일별 오류 출력 가능하도록 개선
개선된 소스
import tkinter as tk
from tkinter import filedialog, messagebox, scrolledtext
import pandas as pd
import smtplib
import os
from dotenv import load_dotenv
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
# 환경 변수 로드
load_dotenv()
EMAIL_ADDRESS = os.getenv("EMAIL_USER")
EMAIL_PASSWORD = os.getenv("EMAIL_PASS")
# 이메일 리스트 저장할 전역 변수
emails = []
email_vars = []
# 이메일 발송 함수
def send_email(subject, body, recipients):
if not EMAIL_ADDRESS or not EMAIL_PASSWORD:
messagebox.showerror("오류", "이메일 계정 정보가 설정되지 않았습니다.")
return
try:
with smtplib.SMTP('smtp.gmail.com', 587) as server:
server.starttls()
server.login(EMAIL_ADDRESS, EMAIL_PASSWORD)
failed_emails = []
for email in recipients:
try:
msg = MIMEMultipart()
msg['From'] = EMAIL_ADDRESS
msg['To'] = email
msg['Subject'] = subject
msg.attach(MIMEText(body, 'plain'))
server.sendmail(EMAIL_ADDRESS, email, msg.as_string())
except Exception as e:
failed_emails.append((email, str(e)))
if failed_emails:
error_msg = "\n".join([f"{email}: {error}" for email, error in failed_emails])
messagebox.showwarning("일부 이메일 실패", f"다음 이메일 전송 실패:\n{error_msg}")
else:
messagebox.showinfo("성공", "이메일이 성공적으로 발송되었습니다.")
except Exception as e:
messagebox.showerror("오류", f"이메일 전송 실패: {e}")
# 엑셀 파일 열기 함수
def open_file():
global emails, email_vars
file_path = filedialog.askopenfilename(filetypes=[("Excel files", "*.xlsx")])
if file_path:
try:
df = pd.read_excel(file_path)
emails = df['Email'].dropna().tolist() # 'Email' 열 가져오기
# 기존 위젯 삭제
for widget in email_list_frame.winfo_children():
widget.destroy()
email_vars.clear()
for email in emails:
var = tk.BooleanVar()
email_vars.append(var)
checkbox = tk.Checkbutton(email_list_frame, text=email, variable=var)
checkbox.pack(anchor="w")
messagebox.showinfo("파일 열기 성공", f"{len(emails)}개의 이메일을 찾았습니다.")
except Exception as e:
messagebox.showerror("오류", f"엑셀 파일을 읽는 중 오류 발생: {e}")
# 선택된 이메일 발송 함수
def send_selected_emails():
subject = subject_entry.get()
body = body_text.get("1.0", tk.END).strip()
recipients = [email for email, var in zip(emails, email_vars) if var.get()]
if not recipients:
messagebox.showwarning("선택 오류", "보낼 이메일을 선택해 주세요.")
return
send_email(subject, body, recipients)
# GUI 설정
root = tk.Tk()
root.title("이메일 발송기")
# 이메일 제목
tk.Label(root, text="이메일 제목").pack()
subject_entry = tk.Entry(root, width=50)
subject_entry.pack()
# 이메일 내용 (스크롤 가능)
tk.Label(root, text="이메일 내용").pack()
body_text = scrolledtext.ScrolledText(root, width=50, height=10)
body_text.pack()
# 이메일 리스트 프레임 (스크롤 포함)
email_list_frame = tk.Frame(root)
email_list_frame.pack()
# 엑셀 파일 열기 버튼
tk.Button(root, text="엑셀 파일 열기", command=open_file).pack()
# 발송 버튼
tk.Button(root, text="선택된 이메일 발송", command=send_selected_emails).pack()
# 실행
root.mainloop()
🔥 개선된 점 정리
1️⃣ 보안 강화 → dotenv 사용하여 이메일 계정 정보 숨김
2️⃣ SMTP 최적화 → with smtplib.SMTP(...) 사용하여 자동 종료
3️⃣ 이메일 전송 오류 처리 → 실패한 이메일 개별 감지 및 알림
4️⃣ 엑셀 데이터 오류 수정 → 전역 변수 emails 제대로 관리
5️⃣ GUI 개선 → 스크롤바 추가하여 긴 텍스트 보기 편하게 변경
이제 .env 파일을 만들어 아래 내용을 넣어줘!
✅ 이제 보안 문제 없이 안전하고 확장 가능하게 동작할 거야!
제 메일을 통해 발송하도록 진행하는 모습입니다.
파일을 만들어 다시 테스트해 보겠습니다.
myEmail.env 파일에 위내용을 넣어 만들어놓고 알려줬습니다.
나:
myEmail.env 파일로 만들었어
chatGPT:
좋아! 🎉 이제 .env 파일을 불러올 때 아래처럼 수정하면 돼.
📌 수정할 부분
그러면 .env 파일이 정상적으로 불러와질 거야.
✅ 이제 실행해보고 잘 동작하는지 확인해봐!
혹시 오류가 발생하면 로그랑 함께 알려줘! 🚀
나:
File "C:\Users\qwe\pythonPG\emailAutoSend.py", line 6, in <module> from dotenv import load_dotenv ModuleNotFoundError: No module named 'dotenv'
chatGPT:
python-dotenv 라이브러리가 설치되지 않은 것 같아!
아래 명령어를 실행해서 설치해주면 돼.
✅ dotenv 설치하기
터미널(명령 프롬프트)에서 실행:
pip install python-dotenv
그리고 다시 프로그램을 실행해봐!
설치 후 재실행해보겠습니다.
이메일은 잘 가져옵니다. 하지만 제가 생각한 것은 이메일을 리스트형태로 스크롤바가 있도록 설정하는 것인데 그 부분이 잘 설명이 안된듯합니다. 일단 발송테스트를 해보고 고도화 작업을 실시해 보겠습니다.
역시 한 번에 되지 않습니다. 오류가 이미지로 되어있어 chatGPT에게 오류를 봐달라고 해봅니다.
앱 비밀번호로 변경하고 다시 시도해 보겠습니다.
찾기가 어려우시면 구글 계정에서 검색란에 "앱 비밀번호"라고 입력하시면 앱 이름을 작성 후 비밀번호가 발급됩니다. 저는 앱이름을 "메일"로 정했습니다.
env 파일을 수정하려고 하는데 암호가 걸려있네요.
액세스 제거 후 편집해 줍니다.
정상적으로 발송이 된 것을 확인했습니다. 메일 받은 것을 확인해 보겠습니다.
gmail
naver
정상적으로 발송되었습니다.
고도화
나:
선택된 이메일들을 보여주는것을 그리드 형태로 10건이 넘어가면 스크롤되게 해주는게 좋을거같아 그리고 GUI를 좀더 이쁘게 만들어줬으면 좋겠어
chatGPT:
좋아! 🎨✨
✅ 선택된 이메일을 10개씩 그리드 형태로 표시
✅ 10건이 넘어가면 자동으로 스크롤 추가
✅ GUI를 좀 더 세련되게 디자인
💡 추가 개선 사항
- ttk.Frame과 Canvas를 활용해 스크롤 가능한 리스트 구현
- ttk.Style()을 이용해 깔끔한 버튼과 입력 필드 스타일 적용
- ttk.LabelFrame을 사용해 UI를 정돈
소스 생략
🎯 개선된 내용
✅ 이메일 목록을 2개씩 가로로 정렬
✅ 10개 이상이면 스크롤 가능하도록 수정
✅ ttk 스타일 적용으로 UI 개선
✅ GUI 전체적인 레이아웃 정리
에러가 발생해서 확인해 보았습니다.
File "C:\Users\qwe\pythonPG\emailAutoSend.py", line 87 global email_frame_inner ^^^^^^^^^^^^^^^^^^^^^^^^ SyntaxError: name 'email_frame_inner' is used prior to global declaration
이 오류는 global 키워드를 사용하려는 변수인 email_frame_inner가 함수 내에서 먼저 참조되고 있다는 뜻입니다. 이 문제는 email_frame_inner가 함수 내에서 참조되기 전에 global 선언이 있어야 하는데, 그렇지 않아서 발생한 것입니다.
def display_emails(email_list):
global email_frame_inner # 'global'을 먼저 선언
email_canvas.delete("all")
email_frame_inner.destroy()
이 부분을 변경해 주겠습니다.
정상적으로 실행됩니다.
이 에러도 해결해야겠군요.
제가 수행하고 에러 나는 부분을 일일이 공유하고 해결하는 것을 보여주는 것은 제가 해결하고 넘어가 버리면 여러분이 따라오실 때 해결이 안 되는 부분이 생길 것 같아 일일이 표기하는 것입니다. 다소 글이 길어지고 에러를 수정하는 것이 다수 나오더라도 이해해 주시고 어떻게 해결해 나가는지 확인해 보시다 보면 아 이건 이렇게 해결하면 되네 라는 감이 오실 것입니다.
에러를 보여주겠습니다.
나:
ChatGPT의 말:
name 'email_list_frame' is not defined 오류는 코드에서 email_list_frame이라는 변수를 참조하려고 했지만, 해당 변수가 정의되지 않았기 때문에 발생한 문제입니다.
이 오류가 발생하는 이유는, 코드에서 email_list_frame이라는 이름을 사용하는 부분이 있지만, 실제로 해당 변수는 정의되지 않았기 때문입니다. 대신, 코드에서는 email_list_container라는 변수를 사용하고 있으므로, email_list_frame 대신 email_list_container를 사용해야 합니다.
수정해야 할 부분은 open_file 함수에서 이메일 목록을 표시하는 부분입니다. 현재 email_list_frame라는 변수를 사용하려고 했지만, 이는 정의되지 않았기 때문에 email_list_container로 변경하면 됩니다.
수정된 코드는 다음과 같습니다:
def open_file():
global emails, email_vars
file_path = filedialog.askopenfilename(filetypes=[("Excel files", "*.xlsx")])
if file_path:
try:
df = pd.read_excel(file_path)
emails = df['Email'].dropna().tolist() # 'Email' 열 가져오기
# 기존 위젯 삭제
for widget in email_list_container.winfo_children(): # 'email_list_frame' 대신 'email_list_container' 사용
widget.destroy()
email_vars.clear()
display_emails(emails)
messagebox.showinfo("파일 열기 성공", f"{len(emails)}개의 이메일을 찾았습니다.")
except Exception as e:
messagebox.showerror("오류", f"엑셀 파일을 읽는 중 오류 발생: {e}")
위 코드에서 email_list_frame을 email_list_container로 변경했으므로, 이제 open_file 함수에서 이메일 목록을 제대로 불러올 수 있을 것입니다. 이렇게 수정 후 다시 실행해 보세요! 문제가 해결되었는지 확인해 주세요.
수정해서 재실행해보겠습니다.
추가 에러가 발생했군요. invalid command name ".!frame.!labelframe.!canvas"
다시 문의합니다.
invalid command name ".!frame.!labelframe.!canvas" 오류는 Tkinter의 위젯을 업데이트하려고 할 때 해당 위젯이 더 이상 존재하지 않는 경우 발생합니다. 이 오류는 email_canvas 또는 email_list_container와 같은 위젯을 삭제하거나 새로 생성하려고 할 때, 이전 위젯이 이미 파괴되었거나 유효하지 않은 상태일 때 발생할 수 있습니다.
주로 아래와 같은 문제에서 발생할 수 있습니다:
- 위젯을 삭제한 후 다시 참조하려는 경우: 위젯을 destroy() 메서드로 삭제한 후, 해당 위젯을 다시 참조하거나 업데이트하려고 할 때 발생할 수 있습니다.
- email_canvas 또는 email_list_container와 같은 위젯이 다른 부분에서 삭제되었거나 생성되지 않았을 경우.
이 문제를 해결하려면, destroy() 메서드를 호출하여 위젯을 삭제하기 전에 해당 위젯이 유효한지 확인하거나, 새로운 위젯을 생성하기 전에 기존 위젯을 적절히 처리해야 합니다.
해결 방법
- email_list_container와 email_canvas를 제대로 초기화하고, 위젯을 업데이트할 때 문제를 피하기 위해 삭제 후 다시 추가하는 방식으로 수정:
코드
# 이메일 리스트를 10개씩 그리드 형태로 표시 (스크롤 포함)
def display_emails(email_list):
global email_frame_inner # 'global'을 먼저 선언
# 기존 이메일 목록 위젯 삭제 전, 존재 여부 확인
if 'email_frame_inner' in globals():
email_frame_inner.destroy() # 기존 위젯을 삭제
email_canvas.delete("all") # 기존 캔버스 내용 삭제
# 이메일 목록을 표시할 새 프레임 생성
email_frame_inner = ttk.Frame(email_canvas)
email_canvas.create_window((0, 0), window=email_frame_inner, anchor="nw")
email_vars.clear()
row, col = 0, 0
for i, email in enumerate(email_list):
var = tk.BooleanVar()
email_vars.append(var)
chk = ttk.Checkbutton(email_frame_inner, text=email, variable=var)
chk.grid(row=row, column=col, sticky="w", padx=5, pady=2)
col += 1
if col >= 2: # 2개씩 한 줄
col = 0
row += 1
email_frame_inner.update_idletasks() # 위젯 업데이트
email_canvas.config(scrollregion=email_canvas.bbox("all")) # 스크롤 영역 업데이트
위 코드에서는 email_frame_inner가 globals()에 존재하는지 먼저 확인한 후, destroy() 메서드를 호출하여 삭제합니다. 그런 다음, 새로 위젯을 생성하고, email_canvas와 email_frame_inner를 다시 초기화합니다.
- email_frame_inner를 생성하는 코드가 적절히 호출되도록 수정: email_frame_inner는 글로벌 변수로 선언되어 있지만, display_emails 함수 내에서 새로 정의되므로 이 부분을 적절히 처리하는 것이 중요합니다.
중요한 점:
- destroy() 메서드는 위젯을 삭제하지만, 해당 위젯의 참조는 여전히 존재할 수 있습니다. 따라서 삭제 후 다시 새로 생성해야 합니다.
- **globals()**를 사용하여 글로벌 변수의 존재 여부를 확인할 수 있습니다. 만약 참조된 변수가 없다면 새로 생성해야 합니다.
위 방법을 적용해 보시고 문제가 해결되는지 확인해 주세요!
제가 변경해야 할 곳을 빨간 표시 해놓았습니다.
무조건 destroy 시키는 것이 아니고 존재 시에만 destroy 시키는 소스로 변경된 모습입니다.
에러가 또 발생했습니다.
아래와 같이 글로벌 변수로 선언해 주겠습니다.
# 이메일 리스트를 10개씩 그리드 형태로 표시 (스크롤 포함)
def display_emails(email_list):
global email_frame_inner # email_frame_inner를 글로벌 변수로 선언
# 기존 이메일 목록 위젯 삭제 전, 존재 여부 확인
if 'email_frame_inner' in globals():
email_frame_inner.destroy() # 기존 위젯을 삭제
email_canvas.delete("all") # 기존 캔버스 내용 삭제
부분 수정을 하다 보니 에러를 잘 못 잡는 듯합니다.
전반적으로 다시 확인 요청을 했습니다.
나:
이 소스를 다시 봐줘
chatGPT:
물론이죠! 주어진 소스를 다시 살펴보겠습니다. 문제는 email_frame_inner에 접근할 수 없다는 오류가 발생하는 부분입니다. 주로 위젯 삭제 후 다시 접근하려는 문제에서 발생하는데, 이 문제를 해결하기 위해 코드를 다시 분석해보겠습니다.
코드 분석
- email_frame_inner가 글로벌로 선언되지 않음
현재 email_frame_inner는 함수 내에서만 선언되고 사용되기 때문에, 다른 함수에서 이 변수를 직접 참조할 수 없습니다. 이를 해결하기 위해 email_frame_inner를 글로벌로 선언하거나, 변수를 매번 새로 생성해야 합니다. - destroy() 호출 후 위젯에 접근 시 발생하는 오류
위젯을 destroy()로 삭제한 후, 그 위젯에 접근하려고 하면 해당 위젯이 삭제된 상태라서 접근할 수 없다는 오류가 발생합니다. 그래서 위젯을 삭제하고 다시 생성하는 방식으로 문제를 해결해야 합니다.
문제 해결을 위한 수정 코드
아래는 email_frame_inner를 글로벌 변수로 선언하여 display_emails 함수에서 접근할 수 있도록 수정한 예시입니다:
소스생략(파일로 첨부)
수정 사항
- email_frame_inner를 글로벌 변수로 선언하여 display_emails 함수 내에서 참조하고, open_file 함수에서 위젯을 삭제할 때에도 참조할 수 있도록 하였습니다.
- open_file 함수에서 이메일 목록을 불러온 후, 기존에 존재하는 email_frame_inner 위젯을 삭제하도록 수정했습니다.
이렇게 수정된 코드에서는 email_frame_inner를 글로벌로 관리하면서, 삭제 후에도 문제 없이 새로 생성할 수 있습니다. 이제 이 코드가 제대로 동작할 것입니다.
문제가 해결되었는지 확인해 주세요!
최종결과
이제 정상적으로 작동을 합니다.
이번에도 경험한 것은 gui를 이쁘게 만들어달라는 요청이 일어나면서 소스 내부에 오류사항들이 생겨난다는 점입니다. gui를 변경할 때 함께 수정되야 될 부분들을 정확하게 수정해주지는 못하는 모습입니다. 하지만 오류를 지속적으로 피드백하면 결국 프로그램은 완성됩니다.
시행착오는 있었지만 엑셀로 된 메일목록에 단체메일을 발송하는 프로그램이 완성되었습니다.
다음번에는 여기서 한발 더 나아가 자동으로 엑셀 대상에게 특정 메일을 정해진 스케줄마다 발송하는 프로그램을 만들어 보도록 하겠습니다.
수고 많으셨습니다. ^^
이상 IT아재였습니다~~
'IT정보 > AI프로그래밍' 카테고리의 다른 글
윈도우 알람및 컴퓨터 자동종료 프로그램 (0) | 2025.03.18 |
---|---|
이메일을 수집해서 엑셀파일로 관리하는 프로그램 (0) | 2025.03.17 |
텍스트와 음성을 특정언어로 변환해주는 프로그램 만들기 (0) | 2025.03.16 |
프린트스크린샷 기능을 단축키로 변경해주는 프로그램 (0) | 2025.03.14 |
내컴퓨터 정보확인하는 프로그램 (0) | 2025.03.14 |