Skip to main content
Glama

MCP Email Server

by ai-zerolab
BSD 3-Clause
83
  • Apple
  • Linux
"""Focused tests to achieve patch coverage for environment variable configuration.""" import os from mcp_email_server.config import EmailSettings, Settings def test_from_env_missing_email_and_password(monkeypatch): """Test return None when email/password missing - covers line 138.""" # No environment variables set result = EmailSettings.from_env() assert result is None # Only email, no password monkeypatch.setenv("MCP_EMAIL_SERVER_EMAIL_ADDRESS", "test@example.com") result = EmailSettings.from_env() assert result is None # Only password, no email monkeypatch.delenv("MCP_EMAIL_SERVER_EMAIL_ADDRESS", raising=False) monkeypatch.setenv("MCP_EMAIL_SERVER_PASSWORD", "pass") result = EmailSettings.from_env() assert result is None def test_from_env_missing_hosts_warning(monkeypatch): """Test logger.warning for missing hosts - covers lines 154-156.""" monkeypatch.setenv("MCP_EMAIL_SERVER_EMAIL_ADDRESS", "test@example.com") monkeypatch.setenv("MCP_EMAIL_SERVER_PASSWORD", "pass") # Missing both hosts result = EmailSettings.from_env() assert result is None # Missing SMTP host monkeypatch.setenv("MCP_EMAIL_SERVER_IMAP_HOST", "imap.test.com") result = EmailSettings.from_env() assert result is None # Missing IMAP host monkeypatch.delenv("MCP_EMAIL_SERVER_IMAP_HOST") monkeypatch.setenv("MCP_EMAIL_SERVER_SMTP_HOST", "smtp.test.com") result = EmailSettings.from_env() assert result is None def test_from_env_exception_handling(monkeypatch): """Test exception handling in try/except - covers lines 177-179.""" monkeypatch.setenv("MCP_EMAIL_SERVER_EMAIL_ADDRESS", "test@example.com") monkeypatch.setenv("MCP_EMAIL_SERVER_PASSWORD", "pass") monkeypatch.setenv("MCP_EMAIL_SERVER_IMAP_HOST", "imap.test.com") monkeypatch.setenv("MCP_EMAIL_SERVER_SMTP_HOST", "smtp.test.com") monkeypatch.setenv("MCP_EMAIL_SERVER_IMAP_PORT", "invalid") # Will cause ValueError result = EmailSettings.from_env() assert result is None def test_from_env_success_with_all_defaults(monkeypatch): """Test successful creation with defaults - covers lines 147-176.""" monkeypatch.setenv("MCP_EMAIL_SERVER_EMAIL_ADDRESS", "user@example.com") monkeypatch.setenv("MCP_EMAIL_SERVER_PASSWORD", "pass") monkeypatch.setenv("MCP_EMAIL_SERVER_IMAP_HOST", "imap.example.com") monkeypatch.setenv("MCP_EMAIL_SERVER_SMTP_HOST", "smtp.example.com") result = EmailSettings.from_env() assert result is not None assert result.account_name == "default" assert result.full_name == "user" assert result.email_address == "user@example.com" assert result.incoming.user_name == "user@example.com" assert result.incoming.port == 993 assert result.outgoing.port == 465 def test_from_env_with_all_vars_set(monkeypatch): """Test with all environment variables set - covers parse_bool branches.""" env_vars = { "MCP_EMAIL_SERVER_ACCOUNT_NAME": "myaccount", "MCP_EMAIL_SERVER_FULL_NAME": "John Doe", "MCP_EMAIL_SERVER_EMAIL_ADDRESS": "john@example.com", "MCP_EMAIL_SERVER_USER_NAME": "johnuser", "MCP_EMAIL_SERVER_PASSWORD": "pass123", "MCP_EMAIL_SERVER_IMAP_HOST": "imap.example.com", "MCP_EMAIL_SERVER_IMAP_PORT": "143", "MCP_EMAIL_SERVER_IMAP_SSL": "false", "MCP_EMAIL_SERVER_SMTP_HOST": "smtp.example.com", "MCP_EMAIL_SERVER_SMTP_PORT": "587", "MCP_EMAIL_SERVER_SMTP_SSL": "no", "MCP_EMAIL_SERVER_SMTP_START_SSL": "yes", "MCP_EMAIL_SERVER_IMAP_USER_NAME": "imap_john", "MCP_EMAIL_SERVER_IMAP_PASSWORD": "imap_pass", "MCP_EMAIL_SERVER_SMTP_USER_NAME": "smtp_john", "MCP_EMAIL_SERVER_SMTP_PASSWORD": "smtp_pass", } for key, value in env_vars.items(): monkeypatch.setenv(key, value) result = EmailSettings.from_env() assert result is not None assert result.account_name == "myaccount" assert result.full_name == "John Doe" assert result.incoming.user_name == "imap_john" assert result.incoming.password == "imap_pass" # noqa: S105 assert result.incoming.port == 143 assert result.incoming.use_ssl is False assert result.outgoing.user_name == "smtp_john" assert result.outgoing.password == "smtp_pass" # noqa: S105 assert result.outgoing.port == 587 assert result.outgoing.use_ssl is False assert result.outgoing.start_ssl is True def test_from_env_boolean_parsing_variations(monkeypatch): """Test various boolean value parsing - covers parse_bool function.""" base_env = { "MCP_EMAIL_SERVER_EMAIL_ADDRESS": "test@example.com", "MCP_EMAIL_SERVER_PASSWORD": "pass", "MCP_EMAIL_SERVER_IMAP_HOST": "imap.test.com", "MCP_EMAIL_SERVER_SMTP_HOST": "smtp.test.com", } # Test "1" = true monkeypatch.setenv("MCP_EMAIL_SERVER_IMAP_SSL", "1") monkeypatch.setenv("MCP_EMAIL_SERVER_SMTP_SSL", "0") for key, value in base_env.items(): monkeypatch.setenv(key, value) result = EmailSettings.from_env() assert result.incoming.use_ssl is True assert result.outgoing.use_ssl is False # Test "on"/"off" monkeypatch.setenv("MCP_EMAIL_SERVER_IMAP_SSL", "on") monkeypatch.setenv("MCP_EMAIL_SERVER_SMTP_START_SSL", "off") result = EmailSettings.from_env() assert result.incoming.use_ssl is True assert result.outgoing.start_ssl is False def test_settings_init_no_env(monkeypatch, tmp_path): """Test Settings.__init__ when no env vars - covers line 211 false branch.""" config_file = tmp_path / "empty.toml" config_file.write_text("") monkeypatch.setenv("MCP_EMAIL_SERVER_CONFIG_PATH", str(config_file)) # Clear any email env vars for key in list(os.environ.keys()): if key.startswith("MCP_EMAIL_SERVER_") and "CONFIG_PATH" not in key: monkeypatch.delenv(key, raising=False) settings = Settings() assert len(settings.emails) == 0 def test_settings_init_add_new_account(monkeypatch, tmp_path): """Test adding new account from env - covers lines 225-226.""" config_file = tmp_path / "empty.toml" config_file.write_text("") monkeypatch.setenv("MCP_EMAIL_SERVER_CONFIG_PATH", str(config_file)) monkeypatch.setenv("MCP_EMAIL_SERVER_EMAIL_ADDRESS", "new@example.com") monkeypatch.setenv("MCP_EMAIL_SERVER_PASSWORD", "newpass") monkeypatch.setenv("MCP_EMAIL_SERVER_IMAP_HOST", "imap.new.com") monkeypatch.setenv("MCP_EMAIL_SERVER_SMTP_HOST", "smtp.new.com") monkeypatch.setenv("MCP_EMAIL_SERVER_ACCOUNT_NAME", "newaccount") settings = Settings() assert len(settings.emails) == 1 assert settings.emails[0].account_name == "newaccount" def test_settings_init_override_existing(monkeypatch, tmp_path): """Test overriding existing TOML account - covers lines 214-222.""" config_file = tmp_path / "config.toml" config_file.write_text(""" [[emails]] account_name = "existing" full_name = "Old Name" email_address = "old@example.com" created_at = "2025-01-01T00:00:00" updated_at = "2025-01-01T00:00:00" [emails.incoming] user_name = "olduser" password = "oldpass" host = "imap.old.com" port = 993 use_ssl = true [emails.outgoing] user_name = "olduser" password = "oldpass" host = "smtp.old.com" port = 465 use_ssl = true """) monkeypatch.setenv("MCP_EMAIL_SERVER_CONFIG_PATH", str(config_file)) monkeypatch.setenv("MCP_EMAIL_SERVER_ACCOUNT_NAME", "existing") monkeypatch.setenv("MCP_EMAIL_SERVER_EMAIL_ADDRESS", "new@example.com") monkeypatch.setenv("MCP_EMAIL_SERVER_PASSWORD", "newpass") monkeypatch.setenv("MCP_EMAIL_SERVER_IMAP_HOST", "imap.new.com") monkeypatch.setenv("MCP_EMAIL_SERVER_SMTP_HOST", "smtp.new.com") settings = Settings() assert len(settings.emails) == 1 assert settings.emails[0].account_name == "existing" assert settings.emails[0].email_address == "new@example.com" # Overridden def test_settings_init_loop_through_multiple_accounts(monkeypatch, tmp_path): """Test loop iteration with multiple accounts - covers lines 214-217.""" config_file = tmp_path / "multi.toml" config_file.write_text(""" [[emails]] account_name = "first" full_name = "First" email_address = "first@example.com" created_at = "2025-01-01T00:00:00" updated_at = "2025-01-01T00:00:00" [emails.incoming] user_name = "first" password = "pass1" host = "imap.first.com" port = 993 use_ssl = true [emails.outgoing] user_name = "first" password = "pass1" host = "smtp.first.com" port = 465 use_ssl = true [[emails]] account_name = "second" full_name = "Second" email_address = "second@example.com" created_at = "2025-01-01T00:00:00" updated_at = "2025-01-01T00:00:00" [emails.incoming] user_name = "second" password = "pass2" host = "imap.second.com" port = 993 use_ssl = true [emails.outgoing] user_name = "second" password = "pass2" host = "smtp.second.com" port = 465 use_ssl = true [[emails]] account_name = "third" full_name = "Third" email_address = "third@example.com" created_at = "2025-01-01T00:00:00" updated_at = "2025-01-01T00:00:00" [emails.incoming] user_name = "third" password = "pass3" host = "imap.third.com" port = 993 use_ssl = true [emails.outgoing] user_name = "third" password = "pass3" host = "smtp.third.com" port = 465 use_ssl = true """) monkeypatch.setenv("MCP_EMAIL_SERVER_CONFIG_PATH", str(config_file)) # Override the third account (forces loop to iterate through all) monkeypatch.setenv("MCP_EMAIL_SERVER_ACCOUNT_NAME", "third") monkeypatch.setenv("MCP_EMAIL_SERVER_EMAIL_ADDRESS", "env@example.com") monkeypatch.setenv("MCP_EMAIL_SERVER_PASSWORD", "envpass") monkeypatch.setenv("MCP_EMAIL_SERVER_IMAP_HOST", "imap.env.com") monkeypatch.setenv("MCP_EMAIL_SERVER_SMTP_HOST", "smtp.env.com") settings = Settings() # Note: Our implementation replaces all TOML with env, so we only get 1 account assert len(settings.emails) == 1 assert settings.emails[0].account_name == "third" assert settings.emails[0].email_address == "env@example.com" def test_email_settings_masked(monkeypatch): """Test the masked() method - covers line 182.""" monkeypatch.setenv("MCP_EMAIL_SERVER_EMAIL_ADDRESS", "test@example.com") monkeypatch.setenv("MCP_EMAIL_SERVER_PASSWORD", "secret123") monkeypatch.setenv("MCP_EMAIL_SERVER_IMAP_HOST", "imap.test.com") monkeypatch.setenv("MCP_EMAIL_SERVER_SMTP_HOST", "smtp.test.com") email = EmailSettings.from_env() assert email is not None masked = email.masked() assert masked.incoming.password == "********" # noqa: S105 assert masked.outgoing.password == "********" # noqa: S105 assert masked.email_address == "test@example.com"

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/ai-zerolab/mcp-email-server'

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