159 lines
6.6 KiB
Python
159 lines
6.6 KiB
Python
from django.core.mail import EmailMultiAlternatives, get_connection
|
|
from django.template.loader import render_to_string
|
|
from django.conf import settings
|
|
import logging
|
|
import time
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
def _send_email_with_retry(email_message, max_retries: int = 3, delay: float = 1.0) -> bool:
|
|
"""
|
|
Send email with retry logic for production reliability.
|
|
Uses Django settings from .env file.
|
|
|
|
Args:
|
|
email_message: EmailMultiAlternatives instance
|
|
max_retries: Maximum number of retry attempts
|
|
delay: Delay between retries in seconds
|
|
|
|
Returns:
|
|
bool: True if email was sent successfully, False otherwise
|
|
"""
|
|
for attempt in range(max_retries + 1):
|
|
try:
|
|
# Test connection before sending (uses EMAIL_BACKEND from settings)
|
|
connection = get_connection()
|
|
connection.open()
|
|
connection.close()
|
|
|
|
# Send the email (uses EMAIL_BACKEND and credentials from settings)
|
|
email_message.send()
|
|
return True
|
|
|
|
except Exception as e:
|
|
logger.warning(f"Email send attempt {attempt + 1} failed: {str(e)}")
|
|
|
|
if attempt < max_retries:
|
|
time.sleep(delay * (2 ** attempt)) # Exponential backoff
|
|
continue
|
|
else:
|
|
logger.error(f"Failed to send email after {max_retries + 1} attempts: {str(e)}")
|
|
return False
|
|
|
|
return False
|
|
|
|
|
|
class CareerEmailService:
|
|
"""Service for handling career-related emails"""
|
|
|
|
def send_application_confirmation(self, application):
|
|
"""
|
|
Send confirmation email to applicant
|
|
"""
|
|
try:
|
|
subject = f"Application Received - {application.job.title}"
|
|
from_email = settings.DEFAULT_FROM_EMAIL
|
|
to_email = [application.email]
|
|
|
|
# Create context for email template
|
|
context = {
|
|
'applicant_name': application.full_name,
|
|
'job_title': application.job.title,
|
|
'job_location': application.job.location,
|
|
'application_date': application.applied_date,
|
|
'logo_url': f'{settings.SITE_URL}/images/logo.png',
|
|
'site_url': settings.SITE_URL,
|
|
}
|
|
|
|
# Render email templates
|
|
text_content = render_to_string('career/application_confirmation.txt', context)
|
|
html_content = render_to_string('career/application_confirmation.html', context)
|
|
|
|
# Create email (uses DEFAULT_FROM_EMAIL from settings)
|
|
email = EmailMultiAlternatives(
|
|
subject=subject,
|
|
body=text_content,
|
|
from_email=from_email, # Uses settings.DEFAULT_FROM_EMAIL
|
|
to=to_email
|
|
)
|
|
email.attach_alternative(html_content, "text/html")
|
|
|
|
# Send email with retry logic (uses EMAIL_BACKEND and credentials from settings)
|
|
success = _send_email_with_retry(email)
|
|
|
|
if success:
|
|
logger.info(f"Confirmation email sent to {application.email}")
|
|
else:
|
|
logger.error(f"Failed to send confirmation email to {application.email} after retries")
|
|
return success
|
|
|
|
except Exception as e:
|
|
logger.error(f"Failed to send confirmation email: {str(e)}", exc_info=True)
|
|
return False
|
|
|
|
def send_application_notification_to_admin(self, application):
|
|
"""
|
|
Send notification email to company about new application
|
|
"""
|
|
try:
|
|
subject = f"New Job Application: {application.job.title} - {application.full_name}"
|
|
from_email = settings.DEFAULT_FROM_EMAIL
|
|
to_email = [settings.COMPANY_EMAIL]
|
|
|
|
# Create context for email template
|
|
context = {
|
|
'applicant_name': application.full_name,
|
|
'applicant_email': application.email,
|
|
'applicant_phone': application.phone,
|
|
'job_title': application.job.title,
|
|
'current_position': application.current_position,
|
|
'current_company': application.current_company,
|
|
'years_of_experience': application.years_of_experience,
|
|
'cover_letter': application.cover_letter,
|
|
'portfolio_url': application.portfolio_url,
|
|
'linkedin_url': application.linkedin_url,
|
|
'github_url': application.github_url,
|
|
'website_url': application.website_url,
|
|
'expected_salary': application.expected_salary,
|
|
'salary_currency': application.salary_currency,
|
|
'available_from': application.available_from,
|
|
'notice_period': application.notice_period,
|
|
'application_date': application.applied_date,
|
|
'resume_url': application.resume.url if application.resume else None,
|
|
'logo_url': f'{settings.SITE_URL}/images/logo.png',
|
|
'site_url': settings.SITE_URL,
|
|
}
|
|
|
|
# Render email templates
|
|
text_content = render_to_string('career/application_notification.txt', context)
|
|
html_content = render_to_string('career/application_notification.html', context)
|
|
|
|
# Create email (uses DEFAULT_FROM_EMAIL and COMPANY_EMAIL from settings)
|
|
email = EmailMultiAlternatives(
|
|
subject=subject,
|
|
body=text_content,
|
|
from_email=from_email, # Uses settings.DEFAULT_FROM_EMAIL
|
|
to=to_email, # Uses settings.COMPANY_EMAIL
|
|
reply_to=[application.email]
|
|
)
|
|
email.attach_alternative(html_content, "text/html")
|
|
|
|
# Attach resume if available
|
|
if application.resume:
|
|
email.attach_file(application.resume.path)
|
|
|
|
# Send email with retry logic (uses EMAIL_BACKEND and credentials from settings)
|
|
success = _send_email_with_retry(email)
|
|
|
|
if success:
|
|
logger.info(f"Admin notification email sent for application from {application.email}")
|
|
else:
|
|
logger.error(f"Failed to send admin notification email for application from {application.email} after retries")
|
|
return success
|
|
|
|
except Exception as e:
|
|
logger.error(f"Failed to send admin notification email: {str(e)}", exc_info=True)
|
|
return False
|
|
|