Skip to content

Commit 1b5b541

Browse files
authored
Revert "fix(email): send iCal invite as attachment instead of data URI (#54)" (#57)
This reverts commit 302fd41.
1 parent 302fd41 commit 1b5b541

File tree

3 files changed

+22
-144
lines changed

3 files changed

+22
-144
lines changed

app/services/email_service.py

Lines changed: 0 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,6 @@
99

1010
from app.utils import EmailSender, SESEmailSender
1111
from app.schemas.email import SendEmailRequestBody, EmailProvider
12-
import base64
13-
import urllib.parse
1412

1513

1614
class EmailService:
@@ -36,79 +34,11 @@ def send_email(self, email_details: SendEmailRequestBody, body: str):
3634
- "error": Error message if the email sending fails.
3735
"""
3836
try:
39-
if email_details.id == 5 and 'iCalendarLink' in email_details.body:
40-
ics_content = self._extract_ics_from_data_url(
41-
email_details.body.get('iCalendarLink', '')
42-
)
43-
if ics_content:
44-
event_name = email_details.body.get('eventName', 'event')
45-
return self._send_email_with_ics_attachment(
46-
email_details, body, event_name, ics_content
47-
)
4837
result = self._send_email_by_provider(email_details, body)
4938
return result
5039
except Exception as error:
5140
self._handle_email_error(error)
5241

53-
def _extract_ics_from_data_url(self, data_url: str) -> str | None:
54-
"""
55-
Extract ICS content from data URL.
56-
Handles formats like: data:text/calendar;charset=utf-8,BEGIN:VCALENDAR...
57-
"""
58-
if not data_url or not data_url.startswith('data:'):
59-
return None
60-
61-
header, data = data_url.split(',', 1)
62-
63-
if 'base64' in header:
64-
decoded = base64.b64decode(data).decode('utf-8')
65-
else:
66-
decoded = urllib.parse.unquote(data)
67-
68-
if decoded.strip().startswith('BEGIN:VCALENDAR'):
69-
return decoded
70-
71-
return None
72-
73-
def _send_email_with_ics_attachment(
74-
self,
75-
email_details: SendEmailRequestBody,
76-
body: str,
77-
event_name: str,
78-
ics_content: str
79-
):
80-
"""
81-
Send email with ICS file as attachment.
82-
"""
83-
provider = email_details.provider
84-
sender = self.email_sender.get(provider)
85-
86-
safe_filename = ''.join(c for c in event_name if c.isalnum() or c in (' ', '-', '_')).strip()
87-
safe_filename = safe_filename[:50] if safe_filename else 'event'
88-
filename = f"{safe_filename}.ics"
89-
90-
if hasattr(sender, 'send_email_with_attachment'):
91-
return sender.send_email_with_attachment(
92-
to_email=email_details.recipient,
93-
subject=email_details.subject,
94-
body=body,
95-
cc=email_details.cc,
96-
bcc=email_details.bcc,
97-
is_html=True,
98-
attachment_content=ics_content,
99-
attachment_filename=filename,
100-
attachment_content_type='text/calendar'
101-
)
102-
103-
return sender.send_email(
104-
to_email=email_details.recipient,
105-
subject=email_details.subject,
106-
body=body,
107-
cc=email_details.cc,
108-
bcc=email_details.bcc,
109-
is_html=True,
110-
)
111-
11242
def _send_email_by_provider(self, email_details: SendEmailRequestBody, body: str):
11343
provider = email_details.provider
11444
sender = self.email_sender.get(provider)

app/utils/email_sender.py

Lines changed: 6 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,6 @@
88
from typing import List
99

1010
from pydantic import EmailStr
11-
from email.mime.multipart import MIMEMultipart
12-
from email.mime.text import MIMEText
13-
from email.mime.application import MIMEApplication
1411

1512

1613
class EmailSender:
@@ -105,12 +102,6 @@ def __init__(
105102
self.aws_secret_key = aws_secret_key
106103
self.aws_region = aws_region
107104
self.aws_email = aws_email
108-
self.ses_client = boto3.client(
109-
"ses",
110-
region_name=self.aws_region,
111-
aws_access_key_id=self.aws_access_key,
112-
aws_secret_access_key=self.aws_secret_key,
113-
)
114105

115106
def send_email(
116107
self,
@@ -122,6 +113,12 @@ def send_email(
122113
is_html: bool = False,
123114
) -> dict:
124115
try:
116+
ses_client = boto3.client(
117+
"ses",
118+
region_name=self.aws_region,
119+
aws_access_key_id=self.aws_access_key,
120+
aws_secret_access_key=self.aws_secret_key,
121+
)
125122
message = {"Subject": {"Data": subject}, "Body": {}}
126123
if is_html:
127124
message["Body"]["Html"] = {"Data": body}
@@ -140,68 +137,3 @@ def send_email(
140137
return {"success": True, "message_id": response["MessageId"]}
141138
except Exception as error:
142139
raise ConnectionError(f"Email sending failed: {str(error)}") from error
143-
144-
def send_email_with_attachment(
145-
self,
146-
to_email: str,
147-
subject: str,
148-
body: str,
149-
attachment_content: str,
150-
attachment_filename: str,
151-
attachment_content_type: str = 'application/octet-stream',
152-
cc: List[EmailStr] = None,
153-
bcc: List[EmailStr] = None,
154-
is_html: bool = True,
155-
) -> dict:
156-
"""
157-
Sends an email with an attachment (like an ICS file) using AWS SES send_raw_email.
158-
"""
159-
try:
160-
msg = MIMEMultipart()
161-
msg['Subject'] = subject
162-
msg['From'] = self.aws_email
163-
msg['To'] = to_email
164-
165-
if cc:
166-
msg['Cc'] = ", ".join(cc)
167-
if bcc:
168-
msg['Bcc'] = ", ".join(bcc)
169-
170-
body_type = 'html' if is_html else 'plain'
171-
msg.attach(MIMEText(body, body_type))
172-
173-
if isinstance(attachment_content, str):
174-
attachment_data = attachment_content.encode('utf-8')
175-
else:
176-
attachment_data = attachment_content
177-
178-
part = MIMEApplication(attachment_data)
179-
180-
part.add_header(
181-
'Content-Disposition',
182-
'attachment',
183-
filename=attachment_filename
184-
)
185-
186-
if attachment_content_type:
187-
part.add_header('Content-Type', attachment_content_type)
188-
189-
msg.attach(part)
190-
191-
destinations = [to_email]
192-
if cc:
193-
destinations.extend(cc)
194-
if bcc:
195-
destinations.extend(bcc)
196-
197-
response = self.ses_client.send_raw_email(
198-
Source=self.aws_email,
199-
Destinations=destinations,
200-
RawMessage={
201-
'Data': msg.as_string(),
202-
}
203-
)
204-
return {'success': True, 'message_id': response['MessageId']}
205-
206-
except Exception as error:
207-
raise ConnectionError(f"Email with attachment failed: {str(error)}") from error

templates/rsvp/ticket.html

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,22 @@
117117
</a>
118118
</td>
119119
</tr>
120+
<tr>
121+
<td style="padding: 10px 20px; border-bottom: 1px solid #2d2d2f;">
122+
<a href="{{iCalendarLink}}" target="_blank" style="text-decoration: none; display: block;">
123+
<table border="0" cellpadding="0" cellspacing="0" width="200" align="center">
124+
<tr>
125+
<td style="width: 32px; text-align: center; vertical-align: middle;">
126+
<img width="24" height="24" src="https://img.icons8.com/color/48/calendar-app.png" style="display: inline-block;"/>
127+
</td>
128+
<td style="vertical-align: middle; text-align: left; padding-left: 12px;">
129+
<span style="color: #e5e5e7; font-size: 14px; font-weight: 500;">iCal</span>
130+
</td>
131+
</tr>
132+
</table>
133+
</a>
134+
</td>
135+
</tr>
120136
<tr>
121137
<td style="padding: 10px 20px; border-radius: 0 0 20px 20px;">
122138
<a href="{{outlookCalendarLink}}" target="_blank" style="text-decoration: none; display: block;">

0 commit comments

Comments
 (0)