Skip to main content
Glama
validators.py5.57 kB
"""Pydantic models for request validation""" from typing import Optional, List, Union from pydantic import BaseModel, field_validator, Field class EmailSearchParams(BaseModel): """Parameters for email search operations""" search_term: str = Field(..., min_length=1, description="Search term to match") days: int = Field(default=7, ge=1, le=30, description="Number of days to look back") folder_name: Optional[str] = Field(default=None, description="Folder name to search") match_all: bool = Field(default=True, description="Match all terms (AND) or any term (OR)") @field_validator("search_term") @classmethod def validate_search_term(cls, v): if not v or not v.strip(): raise ValueError("search_term must not be empty or whitespace") return v.strip() @field_validator("folder_name") @classmethod def validate_folder_name(cls, v): if v is not None and v.lower() in ["null", ""]: return None return v class EmailListParams(BaseModel): """Parameters for listing emails""" days: int = Field(default=7, ge=1, le=30, description="Number of days to look back") folder_name: Optional[str] = Field(default=None, description="Folder name to list from") @field_validator("folder_name") @classmethod def validate_folder_name(cls, v): if v is not None and v.lower() in ["null", ""]: return None return v class EmailReplyParams(BaseModel): """Parameters for replying to an email""" email_number: int = Field(..., ge=1, description="Email's position in cache") reply_text: str = Field(..., min_length=1, description="Reply text content") to_recipients: Optional[Union[str, List[str]]] = Field( default=None, description="To recipients (None preserves original)" ) cc_recipients: Optional[Union[str, List[str]]] = Field( default=None, description="CC recipients (None preserves original)" ) @field_validator("reply_text") @classmethod def validate_reply_text(cls, v): if not v or not v.strip(): raise ValueError("reply_text must not be empty or whitespace") return v @field_validator("to_recipients", "cc_recipients") @classmethod def validate_recipients(cls, v): if v is None: return None # Convert single string to list if isinstance(v, str): if not v.strip(): # If empty or whitespace, treat as None return None v = [v] # Validate each email in list if not isinstance(v, list): raise ValueError("Recipients must be a string or list of strings") # Filter out empty strings and validate remaining emails filtered_emails = [] for email in v: if isinstance(email, str) and email.strip(): filtered_emails.append(email.strip()) # Skip empty strings and None values silently - don't raise errors # Return None if no valid emails remain, otherwise return filtered list return filtered_emails if filtered_emails else None @field_validator("cc_recipients") @classmethod def validate_cc_sender_exclusion(cls, v, info): """Note: This validator cannot access the original email sender at validation time. The actual filtering of original sender from CC will be handled in email_composition.py to ensure the original email sender is not included in CC when replying.""" return v class EmailComposeParams(BaseModel): """Parameters for composing a new email""" recipient_email: str = Field( ..., min_length=1, description="Recipient email address(es) - can be single email or semicolon-separated list", ) subject: str = Field(..., min_length=1, description="Email subject") body: str = Field(..., min_length=1, description="Email body content") cc_email: Optional[str] = Field( default=None, description="CC email address(es) - can be single email or semicolon-separated list", ) @field_validator("recipient_email", "cc_email") @classmethod def validate_email(cls, v): if v is None: return None if not v or not v.strip(): raise ValueError("Email address must not be empty") # Basic email validation for multiple emails (semicolon-separated) import re email_pattern = r"^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$" # Split by semicolon and validate each email emails = [email.strip() for email in v.split(";") if email.strip()] if not emails: raise ValueError("At least one email address must be provided") for email in emails: if not re.match(email_pattern, email): raise ValueError(f"Invalid email address format: {email}") return v.strip() @field_validator("subject", "body") @classmethod def validate_not_empty(cls, v): if not v or not v.strip(): raise ValueError("Field must not be empty or whitespace") return v class PaginationParams(BaseModel): """Parameters for pagination""" page: int = Field(default=1, ge=1, description="Page number (1-based)") per_page: int = Field(default=5, ge=1, le=50, description="Items per page") class EmailNumberParam(BaseModel): """Parameter for operations requiring an email number""" email_number: int = Field(..., ge=1, description="Email number in cache")

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/marlonluo2018/outlook-mcp-server'

If you have feedback or need assistance with the MCP directory API, please join our Discord server