setting, session and profile fix

This commit is contained in:
debu-2 2026-10-07 06:16:26 +05:30
parent 068142ed61
commit a434af224c
34 changed files with 497 additions and 119 deletions

View file

@ -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,