Spaces:
Sleeping
Sleeping
| import os | |
| import smtplib | |
| import logging | |
| from email.mime.multipart import MIMEMultipart | |
| from email.mime.text import MIMEText | |
| from dotenv import load_dotenv | |
| load_dotenv() | |
| logger = logging.getLogger(__name__) | |
| SMTP_HOST = os.getenv("SMTP_HOST", "smtp.gmail.com") | |
| SMTP_PORT = int(os.getenv("SMTP_PORT", 587)) | |
| SMTP_USER = os.getenv("SMTP_USER", "") | |
| SMTP_PASS = os.getenv("SMTP_PASS", "") | |
| FROM_NAME = os.getenv("FROM_NAME", "TalentIQ Recruiter") | |
| def _send_email(to_email: str, subject: str, html_body: str) -> bool: | |
| """Send an HTML email via SMTP.""" | |
| if not SMTP_USER or not SMTP_PASS: | |
| logger.warning(f"[MOCK EMAIL] To: {to_email} | Subject: {subject}") | |
| return True # Mock success for demo | |
| try: | |
| msg = MIMEMultipart("alternative") | |
| msg['From'] = f"{FROM_NAME} <{SMTP_USER}>" | |
| msg['To'] = to_email | |
| msg['Subject'] = subject | |
| msg.attach(MIMEText(html_body, 'html')) | |
| with smtplib.SMTP(SMTP_HOST, SMTP_PORT) as server: | |
| server.ehlo() | |
| server.starttls() | |
| server.login(SMTP_USER, SMTP_PASS) | |
| server.sendmail(SMTP_USER, to_email, msg.as_string()) | |
| logger.info(f"Email sent to {to_email}") | |
| return True | |
| except Exception as e: | |
| logger.error(f"Email failed to {to_email}: {e}") | |
| return False | |
| def schedule_interview(candidate_email: str, candidate_name: str, job_title: str, | |
| interview_datetime: str = None, interview_link: str = None, | |
| candidate_id: int = None) -> bool: | |
| """Send interview invitation email.""" | |
| subject = f"π Interview Invitation β {job_title}" | |
| interview_info = "" | |
| if interview_datetime: | |
| interview_info = f""" | |
| <tr> | |
| <td style="padding:8px 0;color:#374151;"><strong>π Date & Time:</strong></td> | |
| <td style="padding:8px 0;color:#374151;">{interview_datetime}</td> | |
| </tr>""" | |
| if interview_link: | |
| interview_info += f""" | |
| <tr> | |
| <td style="padding:8px 0;color:#374151;"><strong>π Meeting Link:</strong></td> | |
| <td style="padding:8px 0;"><a href="{interview_link}" style="color:#4F46E5;">{interview_link}</a></td> | |
| </tr>""" | |
| html = f""" | |
| <!DOCTYPE html> | |
| <html> | |
| <body style="font-family:Arial,sans-serif;background:#f3f4f6;padding:30px;"> | |
| <div style="max-width:600px;margin:auto;background:#fff;border-radius:12px;overflow:hidden;box-shadow:0 4px 20px rgba(0,0,0,0.1);"> | |
| <div style="background:linear-gradient(135deg,#4F46E5,#7C3AED);padding:30px;text-align:center;"> | |
| <h1 style="color:#fff;margin:0;font-size:24px;">π― TalentIQ ATS</h1> | |
| <p style="color:#C7D2FE;margin:5px 0 0;">Smart Recruitment Platform</p> | |
| </div> | |
| <div style="padding:30px;"> | |
| <h2 style="color:#1F2937;">Congratulations, {candidate_name}! π</h2> | |
| <p style="color:#6B7280;line-height:1.6;"> | |
| We reviewed your application for the <strong>{job_title}</strong> position and are excited to invite you for an interview! | |
| </p> | |
| <div style="background:#EEF2FF;border-radius:8px;padding:20px;margin:20px 0;"> | |
| <h3 style="color:#4F46E5;margin:0 0 15px;">Interview Details</h3> | |
| <table style="width:100%;border-collapse:collapse;"> | |
| {interview_info if interview_info else '<tr><td style="color:#6B7280;">Details will be shared shortly.</td></tr>'} | |
| </table> | |
| </div> | |
| <p style="color:#6B7280;font-size:14px;"> | |
| Please confirm your availability by replying to this email. We look forward to speaking with you! | |
| </p> | |
| <div style="text-align:center;margin-top:25px;"> | |
| <a href="{interview_link or '#'}" style="background:#4F46E5;color:#fff;padding:12px 30px;border-radius:8px;text-decoration:none;font-weight:bold;display:inline-block;"> | |
| Join Interview | |
| </a> | |
| </div> | |
| </div> | |
| <div style="background:#F9FAFB;padding:15px;text-align:center;color:#9CA3AF;font-size:12px;"> | |
| This is an automated message from TalentIQ ATS. Please do not reply directly. | |
| </div> | |
| </div> | |
| </body> | |
| </html> | |
| """ | |
| return _send_email(candidate_email, subject, html) | |
| def send_rejection_email(candidate_email: str, candidate_name: str, job_title: str) -> bool: | |
| """Send professional rejection email.""" | |
| subject = f"Application Update β {job_title}" | |
| html = f""" | |
| <!DOCTYPE html> | |
| <html> | |
| <body style="font-family:Arial,sans-serif;background:#f3f4f6;padding:30px;"> | |
| <div style="max-width:600px;margin:auto;background:#fff;border-radius:12px;overflow:hidden;box-shadow:0 4px 20px rgba(0,0,0,0.1);"> | |
| <div style="background:linear-gradient(135deg,#4F46E5,#7C3AED);padding:30px;text-align:center;"> | |
| <h1 style="color:#fff;margin:0;font-size:24px;">π― TalentIQ ATS</h1> | |
| </div> | |
| <div style="padding:30px;"> | |
| <h2 style="color:#1F2937;">Dear {candidate_name},</h2> | |
| <p style="color:#6B7280;line-height:1.6;"> | |
| Thank you for applying for the <strong>{job_title}</strong> position and your interest in our organization. | |
| </p> | |
| <p style="color:#6B7280;line-height:1.6;"> | |
| After careful consideration, we have decided to move forward with other candidates whose experience more closely matches our current requirements. | |
| </p> | |
| <div style="background:#FEF3C7;border-left:4px solid #F59E0B;padding:15px;border-radius:4px;margin:20px 0;"> | |
| <p style="color:#92400E;margin:0;font-size:14px;"> | |
| π‘ <strong>Tip:</strong> We encourage you to apply for future openings that match your skills. We'll keep your profile on file. | |
| </p> | |
| </div> | |
| <p style="color:#6B7280;font-size:14px;">We wish you the very best in your job search!</p> | |
| </div> | |
| <div style="background:#F9FAFB;padding:15px;text-align:center;color:#9CA3AF;font-size:12px;"> | |
| This is an automated message from TalentIQ ATS. | |
| </div> | |
| </div> | |
| </body> | |
| </html> | |
| """ | |
| return _send_email(candidate_email, subject, html) | |