setting, session and profile fix
This commit is contained in:
parent
068142ed61
commit
a434af224c
34 changed files with 497 additions and 119 deletions
|
|
@ -13,6 +13,7 @@ from app.database import get_mongo_database, get_postgres_session
|
|||
from app.models import Account
|
||||
from app.routers.auth import get_current_account
|
||||
from app.schemas import (
|
||||
EmailAttachmentCreate,
|
||||
EmailCreate,
|
||||
EmailRead,
|
||||
MailAddress,
|
||||
|
|
@ -27,6 +28,7 @@ from app.schemas import (
|
|||
)
|
||||
from app.services.domain_provisioning import get_domain_by_name
|
||||
from app.services.mail_sender import deliver_email
|
||||
from app.services.mime_body_extractor import ExtractedMimePart
|
||||
from app.services.message_ids import canonical_message_id, message_id_fields
|
||||
from app.services.mime_parser import parse_mime
|
||||
from app.services.raw_mime_storage import get_raw_mime_storage
|
||||
|
|
@ -44,8 +46,63 @@ from app.services.mailbox_scope import apply_external_scope
|
|||
from app.services.thread_resolver import ThreadResolution
|
||||
|
||||
MESSAGE_SCOPE_EXTERNAL = "EXTERNAL"
|
||||
MAX_ATTACHMENT_BYTES = 15 * 1024 * 1024
|
||||
MAX_ATTACHMENTS_TOTAL_BYTES = 25 * 1024 * 1024
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def sanitize_attachment_filename(name: str) -> str:
|
||||
cleaned = re.sub(r"[\\/]+", "", (name or "").strip()) or "attachment"
|
||||
return cleaned[:255]
|
||||
|
||||
|
||||
def decode_outbound_attachments(
|
||||
items: list[EmailAttachmentCreate],
|
||||
) -> tuple[list[ExtractedMimePart], list[ExtractedMimePart], list[dict]]:
|
||||
inline_parts: list[ExtractedMimePart] = []
|
||||
file_attachments: list[ExtractedMimePart] = []
|
||||
metadata: list[dict] = []
|
||||
total = 0
|
||||
for item in items:
|
||||
try:
|
||||
payload_bytes = base64.b64decode(item.content_base64, validate=True)
|
||||
except (ValueError, TypeError) as error:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
|
||||
detail=f"Attachment {item.filename} is not valid base64.",
|
||||
) from error
|
||||
if len(payload_bytes) > MAX_ATTACHMENT_BYTES:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
|
||||
detail=f"{item.filename} is larger than 15 MB.",
|
||||
)
|
||||
total += len(payload_bytes)
|
||||
if total > MAX_ATTACHMENTS_TOTAL_BYTES:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
|
||||
detail="Attachments together must be 25 MB or smaller.",
|
||||
)
|
||||
part = ExtractedMimePart(
|
||||
filename=sanitize_attachment_filename(item.filename),
|
||||
content_type=item.content_type or "application/octet-stream",
|
||||
payload=payload_bytes,
|
||||
content_id=item.content_id,
|
||||
disposition=item.disposition,
|
||||
)
|
||||
meta = {
|
||||
"filename": part.filename,
|
||||
"content_type": part.content_type,
|
||||
"size": len(part.payload),
|
||||
"content_id": part.content_id,
|
||||
"disposition": part.disposition,
|
||||
}
|
||||
metadata.append(meta)
|
||||
if part.disposition == "inline":
|
||||
inline_parts.append(part)
|
||||
else:
|
||||
file_attachments.append(part)
|
||||
return inline_parts, file_attachments, metadata
|
||||
|
||||
router = APIRouter(prefix="/emails", tags=["emails"])
|
||||
|
||||
|
||||
|
|
@ -196,6 +253,10 @@ async def create_email(
|
|||
detail="Complete DNS setup for your company domain before sending mail.",
|
||||
)
|
||||
|
||||
inline_parts, file_attachments, attachment_meta = decode_outbound_attachments(
|
||||
payload.attachments
|
||||
)
|
||||
|
||||
created_at = utc_now()
|
||||
sender_name = " ".join(
|
||||
part.strip()
|
||||
|
|
@ -241,7 +302,7 @@ async def create_email(
|
|||
"has_quoted_text": reply_display["has_quoted_text"],
|
||||
"body_text": payload.body_text,
|
||||
"body_html": payload.body_html,
|
||||
"attachments": [],
|
||||
"attachments": attachment_meta,
|
||||
"created_at": created_at,
|
||||
"sent_at": created_at,
|
||||
"status": "queued",
|
||||
|
|
@ -274,6 +335,8 @@ async def create_email(
|
|||
domain=domain,
|
||||
in_reply_to=threading_fields.get("in_reply_to"),
|
||||
references=threading_fields.get("references"),
|
||||
inline_parts=inline_parts,
|
||||
file_attachments=file_attachments,
|
||||
)
|
||||
document["status"] = "accepted"
|
||||
normalized_id = canonical_message_id(internet_message_id)
|
||||
|
|
@ -328,7 +391,7 @@ async def create_email(
|
|||
"recipients": document["to"],
|
||||
"subject": document["subject"],
|
||||
"snippet": document["snippet"],
|
||||
"attachments": [],
|
||||
"attachments": attachment_meta,
|
||||
"status": document["status"],
|
||||
"is_read": True,
|
||||
"is_starred": False,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue