Complete Python Programming Guide: Beginner to Advanced
Table of Contents
1. Python Fundamentals
2. Object-Oriented Programming
3. Data Structures & Collections
4. String Processing & Text Manipulation
5. Regular Expressions
6. Error Handling & Control Flow
7. Type Hints & Modern Python
8. Concurrency & Threading
9. Performance Optimization
10. Design Patterns & Interfaces
11. Email Processing & Automation
12. Advanced Projects
1. Python Fundamentals
1.1 Basic Syntax & Variables
# Variables and basic data types
name = "Alice" # String
age = 25 # Integer
height = 5.6 # Float
is_student = True # Boolean
# Basic operations
total = age + 10
greeting = f"Hello, {name}!" # f-string formatting
print(greeting) # Output: Hello, Alice!
1.2 Control Structures
# If statements
if age >= 18:
print("Adult")
elif age >= 13:
print("Teenager")
else:
print("Child")
# Loops
# For loop
for i in range(5):
print(f"Count: {i}")
# While loop
count = 0
while count < 3:
print(f"While count: {count}")
count += 1
# List comprehension (advanced for loop)
squares = [x**2 for x in range(5)] # [0, 1, 4, 9, 16]
1.3 Functions
# Basic function
def greet(name):
return f"Hello, {name}!"
# Function with default parameters
def greet_with_title(name, title="Mr."):
return f"Hello, {title} {name}!"
# Function with multiple return values
def calculate(a, b):
return a + b, a - b, a * b
sum_result, diff_result, mult_result = calculate(10, 5)
# Lambda functions (anonymous functions)
square = lambda x: x**2
print(square(5)) # Output: 25
2. Object-Oriented Programming
2.1 Classes and Objects (Beginner)
class Person:
# Class attribute (shared by all instances)
species = "Homo sapiens"
# Constructor method
def __init__(self, name, age):
# Instance attributes
[Link] = name
[Link] = age
# Instance method
def introduce(self):
return f"Hi, I'm {[Link]} and I'm {[Link]} years old."
# String representation
def __str__(self):
return f"Person(name='{[Link]}', age={[Link]})"
# Creating objects
person1 = Person("Alice", 25)
person2 = Person("Bob", 30)
print([Link]()) # Hi, I'm Alice and I'm 25 years old.
print(person1) # Person(name='Alice', age=25)
2.2 Inheritance (Intermediate)
class Employee(Person): # Employee inherits from Person
def __init__(self, name, age, employee_id, salary):
super().__init__(name, age) # Call parent constructor
self.employee_id = employee_id
[Link] = salary
# Method overriding
def introduce(self):
base_intro = super().introduce()
return f"{base_intro} I work here as employee #{self.employee_id}."
# New method specific to Employee
def get_annual_salary(self):
return [Link] * 12
# Multiple inheritance
class Manager(Employee):
def __init__(self, name, age, employee_id, salary, team_size):
super().__init__(name, age, employee_id, salary)
self.team_size = team_size
def manage_team(self):
return f"Managing a team of {self.team_size} people."
# Usage
manager = Manager("Carol", 35, "M001", 8000, 10)
print([Link]())
print(manager.manage_team())
2.3 Advanced OOP Concepts
from abc import ABC, abstractmethod
# Abstract base class
class Animal(ABC):
def __init__(self, name):
[Link] = name
@abstractmethod
def make_sound(self):
pass # Must be implemented by subclasses
def sleep(self):
return f"{[Link]} is sleeping."
class Dog(Animal):
def make_sound(self):
return f"{[Link]} says Woof!"
class Cat(Animal):
def make_sound(self):
return f"{[Link]} says Meow!"
# Property decorators
class Circle:
def __init__(self, radius):
self._radius = radius
@property
def radius(self):
return self._radius
@[Link]
def radius(self, value):
if value < 0:
raise ValueError("Radius cannot be negative")
self._radius = value
@property
def area(self):
return 3.14159 * self._radius ** 2
# Class methods and static methods
class MathUtils:
@staticmethod
def add(a, b):
return a + b
@classmethod
def from_string(cls, calc_string):
# Factory method
a, operator, b = calc_string.split()
return [Link](int(a), int(b)) if operator == '+' else None
3. Data Structures & Collections
3.1 Built-in Data Structures
# Lists (mutable, ordered)
fruits = ["apple", "banana", "cherry"]
[Link]("date")
[Link](1, "blueberry")
[Link]("banana")
# List slicing
print(fruits[1:3]) # ['blueberry', 'cherry']
print(fruits[:2]) # ['apple', 'blueberry']
print(fruits[-1]) # Last element
# Tuples (immutable, ordered)
coordinates = (10, 20)
x, y = coordinates # Tuple unpacking
# Dictionaries (mutable, key-value pairs)
person = {
"name": "Alice",
"age": 25,
"city": "New York"
# Dictionary methods
print([Link]()) # dict_keys(['name', 'age', 'city'])
print([Link]()) # dict_values(['Alice', 25, 'New York'])
print([Link]()) # dict_items([('name', 'Alice'), ...])
# Sets (mutable, unique elements)
unique_numbers = {1, 2, 3, 2, 1} # {1, 2, 3}
unique_numbers.add(4)
unique_numbers.discard(2)
3.2 Advanced Collections
from collections import defaultdict, Counter, namedtuple, deque
# defaultdict - provides default values
word_count = defaultdict(int)
text = "hello world hello"
for word in [Link]():
word_count[word] += 1
# Counter - counts elements
counter = Counter("hello world")
print(counter) # Counter({'l': 3, 'o': 2, 'h': 1, 'e': 1, ' ': 1, 'w': 1, 'r': 1, 'd': 1})
# namedtuple - creates tuple subclass with named fields
Point = namedtuple('Point', ['x', 'y'])
p = Point(10, 20)
print(p.x, p.y) # 10 20
# deque - double-ended queue (efficient append/pop from both ends)
queue = deque([1, 2, 3])
[Link](0) # [0, 1, 2, 3]
[Link](4) # [0, 1, 2, 3, 4]
4. String Processing & Text Manipulation
4.1 Basic String Operations
text = " Hello, World! "
# Basic methods
print([Link]()) # " hello, world! "
print([Link]()) # " HELLO, WORLD! "
print([Link]()) # "Hello, World!"
print([Link]("World", "Python")) # " Hello, Python! "
# String formatting
name = "Alice"
age = 25
# Old style (avoid)
old_format = "Name: %s, Age: %d" % (name, age)
# New style
new_format = "Name: {}, Age: {}".format(name, age)
# f-strings (preferred in Python 3.6+)
f_string = f"Name: {name}, Age: {age}"
4.2 Advanced String Processing
# String methods for analysis
text = "The quick brown fox jumps over the lazy dog"
# Checking string properties
print([Link]("The")) # True
print([Link]("dog")) # True
print("fox" in text) # True
# Splitting and joining
words = [Link]() # Split by whitespace
print(words) # ['The', 'quick', 'brown', ...]
# Join words back
rejoined = " ".join(words)
# Split with custom delimiter
csv_data = "apple,banana,cherry"
fruits = csv_data.split(",")
# String validation
email = "user@[Link]"
print([Link]("@")) # Should be 1 for valid email
# Multi-line strings
multiline = """
This is a
multi-line
string
""".strip()
5. Regular Expressions
5.1 Basic Pattern Matching
import re
# Basic pattern matching
text = "Hello, my email is john@[Link]"
pattern = r"\w+@\w+\.\w+"
# Search for pattern
match = [Link](pattern, text)
if match:
print(f"Found email: {[Link]()}") # john@[Link]
# Find all matches
emails = "Contact us at info@[Link] or support@[Link]"
all_emails = [Link](r"\w+@\w+\.\w+", emails)
print(all_emails) # ['info@[Link]', 'support@[Link]']
5.2 Advanced Regex Patterns
# Compiled patterns (more efficient for repeated use)
email_pattern = [Link](r"[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}")
phone_pattern = [Link](r"\(?\d{3}\)?[-.\s]?\d{3}[-.\s]?\d{4}")
# Groups and capturing
text = "John Doe, age 30, lives in New York"
pattern = r"(\w+)\s(\w+),\sage\s(\d+),\slives\sin\s(.+)"
match = [Link](pattern, text)
if match:
first_name, last_name, age, city = [Link]()
print(f"Name: {first_name} {last_name}, Age: {age}, City: {city}")
# Named groups (more readable)
pattern = r"(?P<first>\w+)\s(?P<last>\w+),\sage\s(?P<age>\d+)"
match = [Link](pattern, text)
if match:
print([Link]()) # {'first': 'John', 'last': 'Doe', 'age': '30'}
# Lookahead and lookbehind
# Positive lookahead: (?=pattern)
# Negative lookahead: (?!pattern)
# Positive lookbehind: (?<=pattern)
# Negative lookbehind: (?<!pattern)
# Find words that are followed by numbers
pattern = r"\w+(?=\d)"
text = "item1 product2 service"
matches = [Link](pattern, text) # ['item', 'product']
5.3 Regex Flags and Advanced Features
# Common flags
text = """
John SMITH: john@[Link]
Jane DOE: jane@[Link]
"""
# Case insensitive
pattern = [Link](r"john", [Link])
matches = [Link](text) # ['John', 'john']
# Multiline mode
pattern = [Link](r"^Jane", [Link])
matches = [Link](text) # ['Jane']
# Dotall mode (. matches newlines)
pattern = [Link](r"John.*jane", [Link] | [Link])
# Substitution with functions
def capitalize_match(match):
return [Link]().upper()
text = "hello world"
result = [Link](r"\w+", capitalize_match, text) # "HELLO WORLD"
6. Error Handling & Control Flow
6.1 Basic Exception Handling
# Try-except blocks
def divide_numbers(a, b):
try:
result = a / b
return result
except ZeroDivisionError:
print("Error: Cannot divide by zero!")
return None
except TypeError:
print("Error: Invalid input types!")
return None
# Multiple exceptions
def process_data(data):
try:
# Process the data
number = int(data)
result = 100 / number
return result
except (ValueError, TypeError) as e:
print(f"Input error: {e}")
except ZeroDivisionError as e:
print(f"Math error: {e}")
except Exception as e:
print(f"Unexpected error: {e}")
finally:
# Always executes
print("Processing complete")
6.2 Custom Exceptions
# Custom exception classes
class InvalidEmailError(Exception):
"""Raised when an email address is invalid"""
def __init__(self, email, message="Invalid email address"):
[Link] = email
[Link] = message
super().__init__([Link])
class EmailProcessor:
def validate_email(self, email):
if "@" not in email:
raise InvalidEmailError(email, f"Email '{email}' is missing @ symbol")
if "." not in [Link]("@")[1]:
raise InvalidEmailError(email, f"Email '{email}' has invalid domain")
def process_email(self, email):
try:
self.validate_email(email)
print(f"Processing email: {email}")
except InvalidEmailError as e:
print(f"Email validation failed: {[Link]}")
raise # Re-raise the exception
6.3 Context Managers
# Built-in context managers
with open("[Link]", "r") as file:
content = [Link]()
# File is automatically closed after the block
# Custom context manager using class
class DatabaseConnection:
def __enter__(self):
print("Connecting to database...")
return self
def __exit__(self, exc_type, exc_val, exc_tb):
print("Closing database connection...")
if exc_type:
print(f"An error occurred: {exc_val}")
return False # Don't suppress exceptions
# Custom context manager using contextlib
from contextlib import contextmanager
@contextmanager
def timer():
import time
start = [Link]()
try:
yield
finally:
end = [Link]()
print(f"Execution time: {end - start:.2f} seconds")
# Usage
with timer():
# Some time-consuming operation
sum(range(1000000))
7. Type Hints & Modern Python
7.1 Basic Type Hints
from typing import List, Dict, Optional, Union, Tuple
# Basic type hints
def greet(name: str) -> str:
return f"Hello, {name}!"
def calculate_area(length: float, width: float) -> float:
return length * width
# Collection type hints
def process_numbers(numbers: List[int]) -> Dict[str, int]:
return {
"sum": sum(numbers),
"count": len(numbers),
"max": max(numbers) if numbers else 0
# Optional types (can be None)
def find_user(user_id: int) -> Optional[str]:
users = {1: "Alice", 2: "Bob"}
return [Link](user_id)
# Union types (multiple possible types)
def process_id(user_id: Union[int, str]) -> str:
return f"Processing user: {user_id}"
7.2 Advanced Type Hints
from typing import Callable, Generic, TypeVar, Protocol
from dataclasses import dataclass
# Function type hints
def apply_operation(numbers: List[int], operation: Callable[[int], int]) -> List[int]:
return [operation(num) for num in numbers]
# Usage
result = apply_operation([1, 2, 3], lambda x: x * 2)
# Generic types
T = TypeVar('T')
class Stack(Generic[T]):
def __init__(self) -> None:
self._items: List[T] = []
def push(self, item: T) -> None:
self._items.append(item)
def pop(self) -> T:
return self._items.pop()
# Protocols (structural typing)
class Drawable(Protocol):
def draw(self) -> None: ...
class Circle:
def draw(self) -> None:
print("Drawing a circle")
def render_shape(shape: Drawable) -> None:
[Link]()
# Dataclasses
@dataclass
class Person:
name: str
age: int
email: Optional[str] = None
def is_adult(self) -> bool:
return [Link] >= 18
# Usage
person = Person("Alice", 25, "alice@[Link]")
print([Link]) # Alice
print(person.is_adult()) # True
8. Concurrency & Threading
8.1 Threading Basics
import threading
import time
# Basic threading
def worker(name, delay):
print(f"Worker {name} starting")
[Link](delay)
print(f"Worker {name} finished")
# Create and start threads
thread1 = [Link](target=worker, args=("A", 2))
thread2 = [Link](target=worker, args=("B", 1))
[Link]()
[Link]()
# Wait for threads to complete
[Link]()
[Link]()
print("All threads completed")
8.2 Thread Synchronization
import threading
import time
# Thread-safe counter with Lock
class SafeCounter:
def __init__(self):
self._value = 0
self._lock = [Link]()
def increment(self):
with self._lock:
current = self._value
[Link](0.001) # Simulate some processing
self._value = current + 1
@property
def value(self):
with self._lock:
return self._value
# Event synchronization
def waiter(event):
print("Waiter: waiting for event...")
[Link]()
print("Waiter: event received!")
def setter(event):
[Link](2)
print("Setter: setting event")
[Link]()
event = [Link]()
t1 = [Link](target=waiter, args=(event,))
t2 = [Link](target=setter, args=(event,))
[Link]()
[Link]()
8.3 ThreadPoolExecutor
from [Link] import ThreadPoolExecutor, as_completed
import requests
import time
# Example: Concurrent HTTP requests
def fetch_url(url):
try:
response = [Link](url, timeout=5)
return f"{url}: {response.status_code}"
except Exception as e:
return f"{url}: Error - {e}"
urls = [
"[Link]
"[Link]
"[Link]
# Sequential execution
start_time = [Link]()
sequential_results = [fetch_url(url) for url in urls]
sequential_time = [Link]() - start_time
# Concurrent execution
start_time = [Link]()
with ThreadPoolExecutor(max_workers=3) as executor:
# Submit all tasks
futures = [[Link](fetch_url, url) for url in urls]
# Collect results as they complete
concurrent_results = []
for future in as_completed(futures):
result = [Link]()
concurrent_results.append(result)
concurrent_time = [Link]() - start_time
print(f"Sequential time: {sequential_time:.2f}s")
print(f"Concurrent time: {concurrent_time:.2f}s")
8.4 Async/Await (Modern Concurrency)
import asyncio
import aiohttp
import time
# Async functions
async def fetch_data(session, url):
async with [Link](url) as response:
return await [Link]()
async def main():
urls = [
"[Link]
"[Link]
"[Link]
async with [Link]() as session:
# Create tasks for concurrent execution
tasks = [fetch_data(session, url) for url in urls]
# Wait for all tasks to complete
results = await [Link](*tasks)
return results
# Run async code
if __name__ == "__main__":
start_time = [Link]()
results = [Link](main())
async_time = [Link]() - start_time
print(f"Async time: {async_time:.2f}s")
9. Performance Optimization
9.1 Profiling and Measurement
import time
import cProfile
from functools import wraps
# Timing decorator
def time_it(func):
@wraps(func)
def wrapper(*args, **kwargs):
start = [Link]()
result = func(*args, **kwargs)
end = [Link]()
print(f"{func.__name__} took {end - start:.4f} seconds")
return result
return wrapper
# Memory usage tracking
import tracemalloc
def track_memory(func):
@wraps(func)
def wrapper(*args, **kwargs):
[Link]()
result = func(*args, **kwargs)
current, peak = tracemalloc.get_traced_memory()
[Link]()
print(f"{func.__name__} - Current: {current / 1024 / 1024:.2f} MB, Peak: {peak / 1024 / 1024:.2f} MB")
return result
return wrapper
@time_it
@track_memory
def inefficient_sum(n):
total = 0
for i in range(n):
total += i
return total
@time_it
@track_memory
def efficient_sum(n):
return n * (n - 1) // 2
# Profile with cProfile
def profile_function():
[Link]('inefficient_sum(1000000)')
9.2 Optimization Techniques
# List comprehensions vs loops
import timeit
# Inefficient
def square_numbers_loop(numbers):
result = []
for num in numbers:
[Link](num ** 2)
return result
# Efficient
def square_numbers_comprehension(numbers):
return [num ** 2 for num in numbers]
# Generator expressions (memory efficient)
def square_numbers_generator(numbers):
return (num ** 2 for num in numbers)
# Pre-compile regex patterns
import re
# Inefficient (compiles pattern each time)
def find_emails_inefficient(texts):
results = []
for text in texts:
matches = [Link](r'\w+@\w+\.\w+', text)
[Link](matches)
return results
# Efficient (pre-compiled pattern)
EMAIL_PATTERN = [Link](r'\w+@\w+\.\w+')
def find_emails_efficient(texts):
results = []
for text in texts:
matches = EMAIL_PATTERN.findall(text)
[Link](matches)
return results
# Use sets for membership testing
def find_common_efficient(list1, list2):
set2 = set(list2) # Convert to set once
return [item for item in list1 if item in set2]
9.3 Caching and Memoization
from functools import lru_cache, cache
import time
# LRU Cache (Least Recently Used)
@lru_cache(maxsize=128)
def fibonacci(n):
if n < 2:
return n
return fibonacci(n-1) + fibonacci(n-2)
# Simple cache (Python 3.9+)
@cache
def expensive_computation(x, y):
[Link](1) # Simulate expensive operation
return x * y + x ** y
# Custom caching decorator
def simple_cache(func):
cache_dict = {}
@wraps(func)
def wrapper(*args, **kwargs):
key = str(args) + str(sorted([Link]()))
if key not in cache_dict:
cache_dict[key] = func(*args, **kwargs)
return cache_dict[key]
return wrapper
@simple_cache
def slow_function(n):
[Link](1)
return n ** 2
10. Design Patterns & Interfaces
10.1 Common Design Patterns
# Singleton Pattern
class Singleton:
_instance = None
_initialized = False
def __new__(cls):
if cls._instance is None:
cls._instance = super().__new__(cls)
return cls._instance
def __init__(self):
if not self._initialized:
[Link] = []
self._initialized = True
# Factory Pattern
from abc import ABC, abstractmethod
class Animal(ABC):
@abstractmethod
def make_sound(self):
pass
class Dog(Animal):
def make_sound(self):
return "Woof!"
class Cat(Animal):
def make_sound(self):
return "Meow!"
class AnimalFactory:
@staticmethod
def create_animal(animal_type):
if animal_type.lower() == "dog":
return Dog()
elif animal_type.lower() == "cat":
return Cat()
else:
raise ValueError(f"Unknown animal type: {animal_type}")
# Observer Pattern
class Subject:
def __init__(self):
self._observers = []
self._state = None
def attach(self, observer):
self._observers.append(observer)
def detach(self, observer):
self._observers.remove(observer)
def notify(self):
for observer in self._observers:
[Link](self._state)
def set_state(self, state):
self._state = state
[Link]()
class Observer:
def __init__(self, name):
[Link] = name
def update(self, state):
print(f"{[Link]} received update: {state}")
10.2 Interface Design with Protocols
from typing import Protocol, runtime_checkable
# Define interfaces using Protocol
@runtime_checkable
class EmailSender(Protocol):
def send_email(self, to: str, subject: str, body: str) -> bool:
...
@runtime_checkable
class EmailFetcher(Protocol):
def fetch_emails(self) -> list:
...
# Implementations
class GmailClient:
def send_email(self, to: str, subject: str, body: str) -> bool:
print(f"Sending email to {to}: {subject}")
return True
def fetch_emails(self) -> list:
print("Fetching emails from Gmail")
return ["email1", "email2"]
class OutlookClient:
def send_email(self, to: str, subject: str, body: str) -> bool:
print(f"Sending via Outlook to {to}: {subject}")
return True
def fetch_emails(self) -> list:
print("Fetching emails from Outlook")
return ["email1", "email2", "email3"]
# Usage with interface
def process_emails(client: EmailFetcher & EmailSender):
emails = client.fetch_emails()
client.send_email("admin@[Link]", "Report", f"Processed {len(emails)} emails")
# Works with any implementation
gmail = GmailClient()
outlook = OutlookClient()
process_emails(gmail)
process_emails(outlook)
10.3 Dependency Injection
from abc import ABC, abstractmethod
# Abstract interfaces
class DatabaseInterface(ABC):
@abstractmethod
def save(self, data): pass
@abstractmethod
def fetch(self, id): pass
class LoggerInterface(ABC):
@abstractmethod
def log(self, message): pass
# Concrete implementations
class MySQLDatabase(DatabaseInterface):
def save(self, data):
print(f"Saving to MySQL: {data}")
def fetch(self, id):
return f"Data from MySQL for ID: {id}"
class FileLogger(LoggerInterface):
def log(self, message):
print(f"Log to file: {message}")
# Service that depends on interfaces
class UserService:
def __init__(self, database: DatabaseInterface, logger: LoggerInterface):
[Link] = database
[Link] = logger
def create_user(self, user_data):
[Link](f"Creating user: {user_data}")
[Link](user_data)
[Link]("User created successfully")
# Dependency injection in action
database = MySQLDatabase()
logger = FileLogger()
user_service = UserService(database, logger)
user_service.create_user({"name": "Alice", "email": "alice@[Link]"})
11. Email Processing & Automation
11.1 Email Handling with imaplib
import imaplib
import email
from [Link] import MIMEText
from [Link] import MIMEMultipart
import smtplib
from dataclasses import dataclass
from typing import List, Optional
@dataclass
class Email:
sender: str
recipient: str
subject: str
body: str
date: str
message_id: str
class EmailClient:
def __init__(self, imap_server: str, smtp_server: str, username: str, password: str):
self.imap_server = imap_server
self.smtp_server = smtp_server
[Link] = username
[Link] = password
def fetch_emails(self, folder: str = "INBOX", limit: int = 10) -> List[Email]:
"""Fetch emails from the specified folder"""
emails = []
# Connect to IMAP server
with imaplib.IMAP4_SSL(self.imap_server) as mail:
[Link]([Link], [Link])
[Link](folder)
# Search for emails
status, messages = [Link](None, "ALL")
email_ids = messages[0].split()
# Fetch the most recent emails
for email_id in email_ids[-limit:]:
status, msg_data = [Link](email_id, "(RFC822)")
# Parse email
raw_email = msg_data[0][1]
email_message = email.message_from_bytes(raw_email)
# Extract email content
body = self._extract_body(email_message)
email_obj = Email(
sender=email_message.get("From", ""),
recipient=email_message.get("To", ""),
subject=email_message.get("Subject", ""),
body=body,
date=email_message.get("Date", ""),
message_id=email_message.get("Message-ID", "")
[Link](email_obj)
return emails
def _extract_body(self, email_message) -> str:
"""Extract plain text body from email message"""
body = ""
if email_message.is_multipart():
for part in email_message.walk():
if part.get_content_type() == "text/plain":
body = part.get_payload(decode=True).decode()
break
else:
body = email_message.get_payload(decode=True).decode()
return body
def send_email(self, to: str, subject: str, body: str, cc: List[str] = None) -> bool:
"""Send an email"""
try:
# Create message
msg = MIMEMultipart()
msg['From'] = [Link]
msg['To'] = to
msg['Subject'] = subject
if cc:
msg['Cc'] = ', '.join(cc)
# Attach body
[Link](MIMEText(body, 'plain'))
# Send email
with smtplib.SMTP_SSL(self.smtp_server, 465) as server:
[Link]([Link], [Link])
text = msg.as_string()
recipients = [to]
if cc:
[Link](cc)
[Link]([Link], recipients, text)
return True
except Exception as e:
print(f"Error sending email: {e}")
return False
# Usage example
# email_client = EmailClient(
# imap_server="[Link]",
# smtp_server="[Link]",
# username="your_email@[Link]",
# password="your_app_password"
#)
11.2 Advanced Email Processing
import re
from [Link] import ThreadPoolExecutor, as_completed
from typing import Dict, Callable
from collections import defaultdict
class EmailProcessor:
def __init__(self, email_client: EmailClient):
self.email_client = email_client
[Link] = []
[Link] = []
# Pre-compiled regex patterns for efficiency
[Link] = {
'email': [Link](r'\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,}\b'),
'phone': [Link](r'\(?\d{3}\)?[-.\s]?\d{3}[-.\s]?\d{4}'),
'url': [Link](r'http[s]?://(?:[a-zA-Z]|[0-9]|[$-_@.&+]|[!*\(\),]|(?:%[0-9a-fA-F][0-9a-fA-F]))+'),
'signature': [Link](r'(?:Best regards?|Sincerely|Thanks?|Regards|Kind regards),?\s*\n\s*([A-Za-
z\s]+)', [Link])
def add_filter(self, filter_func: Callable[[Email], bool]):
"""Add a filter function to determine which emails to process"""
[Link](filter_func)
def add_processor(self, processor_func: Callable[[Email], Dict]):
"""Add a processor function to extract data from emails"""
[Link](processor_func)
def filter_emails(self, emails: List[Email]) -> List[Email]:
"""Apply all filters to email list"""
filtered_emails = emails
for filter_func in [Link]:
filtered_emails = [email for email in filtered_emails if filter_func(email)]
return filtered_emails
def extract_contact_info(self, email: Email) -> Dict[str, List[str]]:
"""Extract contact information from email"""
return {
'emails': [Link]['email'].findall([Link]),
'phones': [Link]['phone'].findall([Link]),
'urls': [Link]['url'].findall([Link])
}
def extract_sender_name(self, email: Email) -> Optional[str]:
"""Extract sender name from email signature"""
match = [Link]['signature'].search([Link])
return [Link](1).strip() if match else None
def categorize_email(self, email: Email) -> str:
"""Categorize email based on content"""
subject_lower = [Link]()
body_lower = [Link]()
# Define categories and keywords
categories = {
'job_application': ['application', 'resume', 'cv', 'position', 'job'],
'support_request': ['help', 'issue', 'problem', 'error', 'bug'],
'sales_inquiry': ['price', 'quote', 'purchase', 'buy', 'cost'],
'meeting_request': ['meeting', 'schedule', 'appointment', 'calendar'],
'newsletter': ['unsubscribe', 'newsletter', 'update', 'news']
for category, keywords in [Link]():
if any(keyword in subject_lower or keyword in body_lower for keyword in keywords):
return category
return 'general'
def process_emails_batch(self, emails: List[Email], max_workers: int = 10) -> Dict[str, any]:
"""Process emails in parallel"""
results = {
'total_processed': 0,
'categories': defaultdict(int),
'contact_info': [],
'sender_names': [],
'errors': []
with ThreadPoolExecutor(max_workers=max_workers) as executor:
# Submit processing tasks
futures = {
[Link](self._process_single_email, email): email
for email in emails
# Collect results as they complete
for future in as_completed(futures):
email = futures[future]
try:
email_result = [Link]()
# Aggregate results
results['total_processed'] += 1
results['categories'][email_result['category']] += 1
if email_result['contact_info']:
results['contact_info'].append(email_result['contact_info'])
if email_result['sender_name']:
results['sender_names'].append(email_result['sender_name'])
except Exception as e:
results['errors'].append(f"Error processing email from {[Link]}: {e}")
return dict(results)
def _process_single_email(self, email: Email) -> Dict[str, any]:
"""Process a single email and extract information"""
return {
'category': self.categorize_email(email),
'contact_info': self.extract_contact_info(email),
'sender_name': self.extract_sender_name(email)
def generate_auto_reply(self, email: Email, template_name: str = "default") -> str:
"""Generate automated reply based on email content"""
templates = {
'job_application': """
Dear {sender_name},
Thank you for your interest in our position. We have received your application and will review it carefully.
We will contact you within 5-7 business days regarding the next steps.
Best regards,
HR Team
""",
'support_request': """
Dear {sender_name},
Thank you for contacting our support team. We have received your request and assigned it ticket number
#{ticket_id}.
Our team will respond within 24 hours.
Best regards,
Support Team
""",
'default': """
Dear {sender_name},
Thank you for your email. We have received your message and will respond as soon as possible.
Best regards,
Customer Service Team
"""
sender_name = self.extract_sender_name(email) or "Valued Customer"
category = self.categorize_email(email)
template = [Link](category, templates['default'])
# Generate ticket ID for support requests
import random
ticket_id = [Link](100000, 999999)
return [Link](sender_name=sender_name, ticket_id=ticket_id).strip()
11.3 Email Analytics and Reporting
import [Link] as plt
import pandas as pd
from datetime import datetime, timedelta
from collections import Counter
import seaborn as sns
class EmailAnalytics:
def __init__(self, emails: List[Email]):
[Link] = emails
[Link] = self._emails_to_dataframe()
def _emails_to_dataframe(self) -> [Link]:
"""Convert email list to pandas DataFrame"""
data = []
for email in [Link]:
# Parse date
try:
date_obj = [Link]([Link][:25], "%a, %d %b %Y %H:%M:%S")
except:
date_obj = [Link]()
[Link]({
'sender': [Link],
'subject': [Link],
'date': date_obj,
'body_length': len([Link]),
'word_count': len([Link]()),
'has_attachments': 'attachment' in [Link]()
})
return [Link](data)
def get_email_volume_by_hour(self) -> Dict[int, int]:
"""Get email volume distribution by hour of day"""
return [Link]['date'].[Link].value_counts().to_dict()
def get_top_senders(self, limit: int = 10) -> Dict[str, int]:
"""Get top email senders"""
return [Link]['sender'].value_counts().head(limit).to_dict()
def get_average_response_time(self) -> float:
"""Calculate average time between emails (mock implementation)"""
sorted_emails = [Link].sort_values('date')
time_diffs = sorted_emails['date'].diff().dt.total_seconds() / 3600 # in hours
return time_diffs.mean()
def generate_report(self) -> str:
"""Generate comprehensive email analytics report"""
report = f"""
EMAIL ANALYTICS REPORT
=====================
Total Emails: {len([Link])}
Date Range: {[Link]['date'].min()} to {[Link]['date'].max()}
VOLUME METRICS:
- Average emails per day: {len([Link]) / max(1, ([Link]['date'].max() - [Link]['date'].min()).days):.1f}
- Peak hour: {[Link]['date'].[Link]().iloc[0]}:00
- Average email length: {[Link]['word_count'].mean():.0f} words
TOP SENDERS:
{chr(10).join([f"- {sender}: {count} emails" for sender, count in self.get_top_senders(5).items()])}
CONTENT ANALYSIS:
- Emails with attachments: {[Link]['has_attachments'].sum()}
({[Link]['has_attachments'].mean()*100:.1f}%)
- Longest email: {[Link]['word_count'].max()} words
- Shortest email: {[Link]['word_count'].min()} words
"""
return [Link]()
def plot_email_trends(self):
"""Create visualization of email trends"""
fig, axes = [Link](2, 2, figsize=(15, 10))
# Daily email volume
daily_volume = [Link]([Link]['date'].[Link]).size()
axes[0, 0].plot(daily_volume.index, daily_volume.values)
axes[0, 0].set_title('Daily Email Volume')
axes[0, 0].set_xlabel('Date')
axes[0, 0].set_ylabel('Number of Emails')
# Hourly distribution
hourly_dist = [Link]['date'].[Link].value_counts().sort_index()
axes[0, 1].bar(hourly_dist.index, hourly_dist.values)
axes[0, 1].set_title('Email Distribution by Hour')
axes[0, 1].set_xlabel('Hour of Day')
axes[0, 1].set_ylabel('Number of Emails')
# Email length distribution
axes[1, 0].hist([Link]['word_count'], bins=30, alpha=0.7)
axes[1, 0].set_title('Email Length Distribution')
axes[1, 0].set_xlabel('Word Count')
axes[1, 0].set_ylabel('Frequency')
# Top senders
top_senders = self.get_top_senders(10)
axes[1, 1].barh(list(top_senders.keys()), list(top_senders.values()))
axes[1, 1].set_title('Top 10 Email Senders')
axes[1, 1].set_xlabel('Number of Emails')
plt.tight_layout()
[Link]()
# Usage example
def demo_email_processing():
# Mock email data for demonstration
sample_emails = [
Email("john@[Link]", "hr@[Link]", "Job Application - Software Engineer",
"Dear Hiring Manager,\n\nI am writing to apply for the software engineer position...\n\nBest
regards,\nJohn Smith",
"Mon, 01 Jan 2024 10:30:00", "msg001"),
Email("support@[Link]", "help@[Link]", "Technical Issue - Login Problem",
"Hello,\n\nI'm having trouble logging into my account...\n\nThanks,\nSarah Johnson",
"Mon, 01 Jan 2024 14:15:00", "msg002")
]
# Create processor
processor = EmailProcessor(None)
# Add filters
processor.add_filter(lambda email: len([Link]) > 50) # Filter short emails
# Process emails
results = processor.process_emails_batch(sample_emails)
print("Processing Results:", results)
# Generate analytics
analytics = EmailAnalytics(sample_emails)
print(analytics.generate_report())
12. Advanced Projects
12.1 Complete Email Automation System
import asyncio
import aiohttp
from typing import List, Dict, Optional, Callable
from dataclasses import dataclass, field
from datetime import datetime, timedelta
import json
import logging
# Configure logging
[Link](level=[Link])
logger = [Link](__name__)
@dataclass
class EmailRule:
"""Represents a rule for email processing"""
name: str
condition: Callable[[Email], bool]
action: Callable[[Email], bool]
priority: int = 0
enabled: bool = True
created_at: datetime = field(default_factory=[Link])
class EmailAutomationEngine:
"""Advanced email automation system"""
def __init__(self, email_client: EmailClient):
self.email_client = email_client
[Link]: List[EmailRule] = []
[Link] = {
'emails_processed': 0,
'rules_executed': 0,
'errors': 0,
'start_time': [Link]()
def add_rule(self, rule: EmailRule):
"""Add an automation rule"""
[Link](rule)
# Sort rules by priority (higher priority first)
[Link](key=lambda r: [Link], reverse=True)
[Link](f"Added rule: {[Link]} (priority: {[Link]})")
def remove_rule(self, rule_name: str):
"""Remove a rule by name"""
[Link] = [rule for rule in [Link] if [Link] != rule_name]
[Link](f"Removed rule: {rule_name}")
async def process_emails_async(self, check_interval: int = 300):
"""Continuously process emails with async support"""
[Link](f"Starting email automation (check interval: {check_interval}s)")
while True:
try:
# Fetch new emails
emails = self.email_client.fetch_emails(limit=50)
[Link](f"Fetched {len(emails)} emails")
# Process emails with rules
await self._apply_rules_async(emails)
# Wait before next check
await [Link](check_interval)
except Exception as e:
[Link](f"Error in email processing loop: {e}")
[Link]['errors'] += 1
await [Link](60) # Wait 1 minute before retrying
async def _apply_rules_async(self, emails: List[Email]):
"""Apply rules to emails asynchronously"""
tasks = []
for email in emails:
for rule in [Link]:
if [Link]:
task = asyncio.create_task(self._execute_rule(email, rule))
[Link](task)
# Execute all rules concurrently
await [Link](*tasks, return_exceptions=True)
async def _execute_rule(self, email: Email, rule: EmailRule):
"""Execute a single rule on an email"""
try:
if [Link](email):
[Link](f"Executing rule '{[Link]}' for email: {[Link]}")
success = await asyncio.to_thread([Link], email)
if success:
[Link]['rules_executed'] += 1
[Link](f"Rule '{[Link]}' executed successfully")
else:
[Link](f"Rule '{[Link]}' failed to execute")
except Exception as e:
[Link](f"Error executing rule '{[Link]}': {e}")
[Link]['errors'] += 1
def get_stats(self) -> Dict:
"""Get automation statistics"""
runtime = [Link]() - [Link]['start_time']
return {
**[Link],
'runtime_hours': runtime.total_seconds() / 3600,
'emails_per_hour': [Link]['emails_processed'] / max(1, runtime.total_seconds() / 3600),
'active_rules': len([rule for rule in [Link] if [Link]])
# Example rules and usage
class EmailRules:
"""Collection of common email automation rules"""
@staticmethod
def create_job_application_rule(email_client: EmailClient) -> EmailRule:
"""Auto-respond to job applications"""
def condition(email: Email) -> bool:
keywords = ['job', 'application', 'resume', 'position', 'career']
subject_lower = [Link]()
return any(keyword in subject_lower for keyword in keywords)
def action(email: Email) -> bool:
response = f"""
Dear Applicant,
Thank you for your interest in our company. We have received your job application
and will review it carefully.
Our HR team will contact you within 5-7 business days if your qualifications
match our current openings.
Best regards,
Human Resources Team
""".strip()
return email_client.send_email(
to=[Link],
subject=f"Re: {[Link]}",
body=response
return EmailRule(
name="job_application_auto_reply",
condition=condition,
action=action,
priority=10
@staticmethod
def create_spam_filter_rule() -> EmailRule:
"""Mark suspicious emails as spam"""
def condition(email: Email) -> bool:
spam_indicators = [
'urgent', 'act now', 'limited time', 'click here',
'free money', 'guaranteed', 'no risk'
content = ([Link] + ' ' + [Link]).lower()
return sum(indicator in content for indicator in spam_indicators) >= 2
def action(email: Email) -> bool:
[Link](f"Potential spam detected from {[Link]}: {[Link]}")
# In a real system, you would move to spam folder or flag
return True
return EmailRule(
name="spam_filter",
condition=condition,
action=action,
priority=100 # High priority
# Complete demo system
async def demo_automation_system():
"""Demonstrate the complete email automation system"""
# Create email client (mock for demo)
class MockEmailClient:
def fetch_emails(self, limit=10):
return [
Email("applicant@[Link]", "hr@[Link]",
"Job Application - Senior Developer",
"I would like to apply for the senior developer position...",
[Link]().isoformat(), "msg001"),
Email("spam@[Link]", "info@[Link]",
"URGENT: Act Now! Free Money Guaranteed!",
"Click here for free money with no risk!",
[Link]().isoformat(), "msg002")
def send_email(self, to, subject, body):
print(f"EMAIL SENT TO {to}: {subject}")
return True
# Create automation engine
email_client = MockEmailClient()
automation = EmailAutomationEngine(email_client)
# Add rules
job_rule = EmailRules.create_job_application_rule(email_client)
spam_rule = EmailRules.create_spam_filter_rule()
automation.add_rule(job_rule)
automation.add_rule(spam_rule)
# Run one cycle for demo
emails = email_client.fetch_emails()
await automation._apply_rules_async(emails)
# Print statistics
print("\nAutomation Statistics:")
print([Link](automation.get_stats(), indent=2, default=str))
# Run the demo
if __name__ == "__main__":
[Link](demo_automation_system())
12.2 Performance Monitoring and Optimization
import psutil
import threading
from contextlib import contextmanager
from typing import Generator, Dict, Any
import json
class PerformanceMonitor:
"""Monitor system and application performance"""
def __init__(self):
[Link] = {}
[Link] = False
self.monitor_thread = None
def start_monitoring(self, interval: float = 1.0):
"""Start background performance monitoring"""
if [Link]:
return
[Link] = True
self.monitor_thread = [Link](
target=self._monitor_loop,
args=(interval,),
daemon=True
self.monitor_thread.start()
[Link]("Performance monitoring started")
def stop_monitoring(self):
"""Stop background monitoring"""
[Link] = False
if self.monitor_thread:
self.monitor_thread.join()
[Link]("Performance monitoring stopped")
def _monitor_loop(self, interval: float):
"""Background monitoring loop"""
while [Link]:
[Link]({
'timestamp': [Link]().isoformat(),
'cpu_percent': psutil.cpu_percent(),
'memory_percent': psutil.virtual_memory().percent,
'disk_io': psutil.disk_io_counters()._asdict() if psutil.disk_io_counters() else {},
'network_io': psutil.net_io_counters()._asdict()
})
[Link](interval)
@contextmanager
def measure_operation(self, operation_name: str) -> Generator[Dict[str, Any], None, None]:
"""Context manager to measure operation performance"""
start_time = [Link]()
start_memory = [Link]().memory_info().rss
operation_metrics = {
'operation': operation_name,
'start_time': start_time
}
try:
yield operation_metrics
finally:
end_time = [Link]()
end_memory = [Link]().memory_info().rss
operation_metrics.update({
'duration': end_time - start_time,
'memory_delta': end_memory - start_memory,
'end_time': end_time
})
[Link](f"Operation '{operation_name}' completed in {operation_metrics['duration']:.2f}s")
def get_current_metrics(self) -> Dict[str, Any]:
"""Get current system metrics"""
return [Link]()
# Enhanced EmailProcessor with monitoring
class MonitoredEmailProcessor(EmailProcessor):
"""EmailProcessor with built-in performance monitoring"""
def __init__(self, email_client: EmailClient):
super().__init__(email_client)
[Link] = PerformanceMonitor()
self.operation_stats = defaultdict(list)
def process_emails_with_monitoring(self) -> Dict[str, Any]:
"""Process emails with comprehensive monitoring"""
[Link].start_monitoring()
try:
with [Link].measure_operation("full_email_processing") as metrics:
# Fetch emails
with [Link].measure_operation("email_fetch") as fetch_metrics:
emails = self.email_client.fetch_emails()
fetch_metrics['email_count'] = len(emails)
# Filter emails
with [Link].measure_operation("email_filtering") as filter_metrics:
filtered_emails = self.filter_emails(emails)
filter_metrics['filtered_count'] = len(filtered_emails)
# Process emails
with [Link].measure_operation("email_batch_processing") as process_metrics:
results = self.process_emails_batch(filtered_emails)
process_metrics['processed_count'] = results['responses_sent']
# Compile final results
final_results = {
**results,
'performance_metrics': {
'total_duration': metrics['duration'],
'fetch_duration': fetch_metrics['duration'],
'filter_duration': filter_metrics['duration'],
'process_duration': process_metrics['duration'],
'emails_per_second': len(filtered_emails) / max(0.001, process_metrics['duration']),
'system_metrics': [Link].get_current_metrics()
return final_results
finally:
[Link].stop_monitoring()
# Example usage and testing
def benchmark_email_processing():
"""Benchmark different email processing approaches"""
# Mock data for testing
mock_emails = [
Email(f"user{i}@[Link]", "system@[Link]",
f"Test Email {i} - pseudo internship interest",
f"Hello,\n\nThis is test email {i}.\n\nBest regards,\nUser {i}",
[Link]().isoformat(), f"msg{i:03d}")
for i in range(100)
class MockEmailClient:
def __init__(self, emails):
[Link] = emails
def fetch_emails(self, limit=None):
return [Link][:limit] if limit else [Link]
def send_email(self, to, subject, body):
[Link](0.01) # Simulate network delay
return True
# Test different configurations
configurations = [
{"max_workers": 1, "name": "Sequential"},
{"max_workers": 5, "name": "5 Workers"},
{"max_workers": 10, "name": "10 Workers"},
{"max_workers": 20, "name": "20 Workers"}
results = {}
for config in configurations:
print(f"\n--- Testing {config['name']} ---")
email_client = MockEmailClient(mock_emails)
processor = MonitoredEmailProcessor(email_client)
# Override max_workers for this test
original_method = processor.process_emails_batch
def test_process(emails, max_workers=config['max_workers']):
return original_method(emails, max_workers)
processor.process_emails_batch = test_process
# Run test
result = processor.process_emails_with_monitoring()
results[config['name']] = result['performance_metrics']
print(f"Duration: {result['performance_metrics']['total_duration']:.2f}s")
print(f"Emails/sec: {result['performance_metrics']['emails_per_second']:.1f}")
# Print comparison
print("\n" + "="*50)
print("PERFORMANCE COMPARISON")
print("="*50)
for name, metrics in [Link]():
print(f"{name:15} | {metrics['total_duration']:6.2f}s | {metrics['emails_per_second']:6.1f}/sec")
if __name__ == "__main__":
benchmark_email_processing()
12.3 Machine Learning Integration
import numpy as np
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.naive_bayes import MultinomialNB
from [Link] import Pipeline
from sklearn.model_selection import train_test_split
from [Link] import classification_report, accuracy_score
import pickle
import os
from typing import Tuple, List
class EmailClassifier:
"""Machine learning-based email classifier"""
def __init__(self, model_path: str = "email_classifier.pkl"):
self.model_path = model_path
[Link] = None
[Link] = []
self.is_trained = False
def prepare_training_data(self, emails: List[Email]) -> Tuple[List[str], List[str]]:
"""Prepare training data from emails"""
texts = []
labels = []
for email in emails:
# Combine subject and body for better classification
full_text = f"{[Link]} {[Link]}"
[Link](full_text)
# Use a simple rule-based labeling for demonstration
# In real scenarios, you would have manually labeled data
label = self._auto_label_email(email)
[Link](label)
return texts, labels
def _auto_label_email(self, email: Email) -> str:
"""Auto-label emails based on keywords (for demo purposes)"""
subject_body = ([Link] + " " + [Link]).lower()
if any(word in subject_body for word in ['job', 'application', 'resume', 'position']):
return 'job_application'
elif any(word in subject_body for word in ['support', 'help', 'issue', 'problem']):
return 'support'
elif any(word in subject_body for word in ['meeting', 'schedule', 'appointment']):
return 'meeting'
elif any(word in subject_body for word in ['invoice', 'payment', 'bill', 'purchase']):
return 'finance'
else:
return 'general'
def train(self, emails: List[Email], test_size: float = 0.2):
"""Train the email classifier"""
print("Preparing training data...")
texts, labels = self.prepare_training_data(emails)
# Split data
X_train, X_test, y_train, y_test = train_test_split(
texts, labels, test_size=test_size, random_state=42, stratify=labels
print(f"Training on {len(X_train)} samples, testing on {len(X_test)} samples")
# Create pipeline with TF-IDF and Naive Bayes
[Link] = Pipeline([
('tfidf', TfidfVectorizer(
max_features=5000,
stop_words='english',
ngram_range=(1, 2),
min_df=2
)),
('classifier', MultinomialNB(alpha=0.1))
])
# Train the model
print("Training classifier...")
[Link](X_train, y_train)
# Evaluate
y_pred = [Link](X_test)
accuracy = accuracy_score(y_test, y_pred)
print(f"Training completed! Accuracy: {accuracy:.3f}")
print("\nClassification Report:")
print(classification_report(y_test, y_pred))
# Store categories and mark as trained
[Link] = list(set(labels))
self.is_trained = True
# Save model
self.save_model()
def predict(self, email: Email) -> Tuple[str, float]:
"""Predict email category and confidence"""
if not self.is_trained:
raise ValueError("Model must be trained before making predictions")
full_text = f"{[Link]} {[Link]}"
prediction = [Link]([full_text])[0]
# Get prediction probabilities
probabilities = [Link].predict_proba([full_text])[0]
confidence = max(probabilities)
return prediction, confidence
def predict_batch(self, emails: List[Email]) -> List[Tuple[str, float]]:
"""Predict categories for multiple emails"""
if not self.is_trained:
raise ValueError("Model must be trained before making predictions")
texts = [f"{[Link]} {[Link]}" for email in emails]
predictions = [Link](texts)
probabilities = [Link].predict_proba(texts)
results = []
for pred, probs in zip(predictions, probabilities):
confidence = max(probs)
[Link]((pred, confidence))
return results
def save_model(self):
"""Save trained model to disk"""
if [Link] is None:
raise ValueError("No trained model to save")
model_data = {
'pipeline': [Link],
'categories': [Link],
'is_trained': self.is_trained
with open(self.model_path, 'wb') as f:
[Link](model_data, f)
print(f"Model saved to {self.model_path}")
def load_model(self):
"""Load trained model from disk"""
if not [Link](self.model_path):
raise FileNotFoundError(f"Model file {self.model_path} not found")
with open(self.model_path, 'rb') as f:
model_data = [Link](f)
[Link] = model_data['pipeline']
[Link] = model_data['categories']
self.is_trained = model_data['is_trained']
print(f"Model loaded from {self.model_path}")
class SmartEmailProcessor(EmailProcessor):
"""Email processor enhanced with machine learning"""
def __init__(self, email_client: EmailClient):
super().__init__(email_client)
[Link] = EmailClassifier()
self.smart_responses = {
'job_application': self._generate_job_response,
'support': self._generate_support_response,
'meeting': self._generate_meeting_response,
'finance': self._generate_finance_response,
'general': self._generate_general_response
def train_classifier(self, training_emails: List[Email]):
"""Train the ML classifier with historical emails"""
print("Training email classifier...")
[Link](training_emails)
def process_emails_smart(self) -> Dict[str, Any]:
"""Process emails using ML classification"""
# Fetch emails
emails = self.email_client.fetch_emails()
filtered_emails = self.filter_emails(emails)
# Classify emails
classifications = [Link].predict_batch(filtered_emails)
# Process each email based on its classification
results = {
'total_emails': len(emails),
'filtered_emails': len(filtered_emails),
'classifications': {},
'responses_sent': 0,
'high_confidence_predictions': 0
}
for email, (category, confidence) in zip(filtered_emails, classifications):
# Track classifications
if category not in results['classifications']:
results['classifications'][category] = 0
results['classifications'][category] += 1
# Track high confidence predictions
if confidence > 0.8:
results['high_confidence_predictions'] += 1
# Generate and send smart response
if confidence > 0.6: # Only respond if reasonably confident
response = self.smart_responses[category](email, confidence)
if self.email_client.send_email(
to=[Link],
subject=f"Re: {[Link]}",
body=response
):
results['responses_sent'] += 1
return results
def _generate_job_response(self, email: Email, confidence: float) -> str:
name = self.extract_name_from_email([Link]) or "Applicant"
return f"""Dear {name},
Thank you for your interest in our company and for submitting your job application.
Our HR team has received your application and will review it thoroughly. We appreciate
your interest in joining our team and will contact you within 5-7 business days
regarding the next steps in our hiring process.
If you have any questions in the meantime, please don't hesitate to contact us.
Best regards,
Human Resources Team
---
This is an automated response generated with {confidence*100:.1f}% confidence.
"""
def _generate_support_response(self, email: Email, confidence: float) -> str:
name = self.extract_name_from_email([Link]) or "Valued Customer"
import random
ticket_id = [Link](100000, 999999)
return f"""Dear {name},
Thank you for contacting our support team. We have received your request and
assigned it ticket number #{ticket_id}.
Our technical support specialists will review your issue and respond within
24 hours during business hours.
For urgent matters, please call our support hotline at 1-800-SUPPORT.
Best regards,
Technical Support Team
---
Ticket ID: #{ticket_id}
Confidence: {confidence*100:.1f}%
"""
def _generate_meeting_response(self, email: Email, confidence: float) -> str:
name = self.extract_name_from_email([Link]) or "Colleague"
return f"""Dear {name},
Thank you for your meeting request. I have received your message and will
review my calendar to find a suitable time.
I will respond with available time slots within 24 hours. Please let me know
if you have any specific time preferences or requirements for our meeting.
Best regards,
Assistant
---
Auto-classified as meeting request ({confidence*100:.1f}% confidence)
"""
def _generate_finance_response(self, email: Email, confidence: float) -> str:
name = self.extract_name_from_email([Link]) or "Customer"
return f"""Dear {name},
Thank you for your financial inquiry. We have received your message regarding
billing/payment matters.
Our accounting department will review your request and respond within 2-3
business days. For immediate assistance with urgent payment matters, please
contact our billing department directly at billing@[Link].
Best regards,
Finance Team
---
Classified as finance-related ({confidence*100:.1f}% confidence)
"""
def _generate_general_response(self, email: Email, confidence: float) -> str:
name = self.extract_name_from_email([Link]) or "Valued Contact"
return f"""Dear {name},
Thank you for your email. We have received your message and will review it carefully.
Someone from our team will respond to you within 2-3 business days. If your
matter is urgent, please don't hesitate to call us directly.
Best regards,
Customer Service Team
---
General inquiry (classified with {confidence*100:.1f}% confidence)
"""
# Demo and testing
def demo_ml_email_processing():
"""Demonstrate ML-enhanced email processing"""
# Create sample training data
training_emails = [
Email("job1@[Link]", "hr@[Link]", "Software Engineer Application",
"Dear HR, I am applying for the software engineer position. Please find my resume attached. Best
regards, John Smith",
"2024-01-01", "1"),
Email("support1@[Link]", "help@[Link]", "Login Issue",
"Hello, I cannot log into my account. Please help. Thanks, Sarah",
"2024-01-01", "2"),
Email("partner@[Link]", "meetings@[Link]", "Schedule Meeting",
"Hi, can we schedule a meeting next week to discuss the project? Regards, Mike",
"2024-01-01", "3"),
# Add more training examples...
# Mock email client
class MockMLClient:
def fetch_emails(self, limit=10):
return [
Email("newapplicant@[Link]", "hr@[Link]", "Job Application - Data Scientist",
"I would like to apply for the data scientist position posted on your website.",
"2024-01-02", "new1"),
Email("customer@[Link]", "support@[Link]", "Technical Problem",
"I'm experiencing issues with the software. It keeps crashing.",
"2024-01-02", "new2")
def send_email(self, to, subject, body):
print(f"\n--- EMAIL SENT TO {to} ---")
print(f"Subject: {subject}")
print(f"Body: {body[:200]}...")
return True
# Create and train smart processor
email_client = MockMLClient()
processor = SmartEmailProcessor(email_client)
print("Training ML classifier...")
processor.train_classifier(training_emails)
print("\nProcessing new emails with ML classification...")
results = processor.process_emails_smart()
print(f"\nResults: {[Link](results, indent=2)}")
if __name__ == "__main__":
demo_ml_email_processing()
Learning Path and Next Steps
Beginner Path (Weeks 1-4)
1. Week 1: Python fundamentals, variables, control structures
2. Week 2: Functions, basic OOP, classes and objects
3. Week 3: Data structures, lists, dictionaries, string processing
4. Week 4: File handling, basic error handling
Intermediate Path (Weeks 5-8)
1. Week 5: Advanced OOP, inheritance, polymorphism
2. Week 6: Regular expressions, text processing
3. Week 7: Type hints, modern Python features
4. Week 8: Basic threading and concurrency
Advanced Path (Weeks 9-12)
1. Week 9: Advanced concurrency, async/await
2. Week 10: Performance optimization, profiling
3. Week 11: Design patterns, interfaces
4. Week 12: Email processing and automation
Expert Path (Months 4-6)
1. Month 4: Machine learning integration, data science
2. Month 5: Web frameworks, APIs, databases
3. Month 6: System design, scalability, deployment
Practice Projects
1. Beginner: Personal task manager
2. Intermediate: Web scraper with email notifications
3. Advanced: Complete email automation system
4. Expert: ML-powered email classification service
Additional Resources
• Books: "Python Tricks" by Dan Bader, "Effective Python" by Brett Slatkin
• Practice: LeetCode, HackerRank, CodeWars
• Documentation: Official Python docs, PEP guidelines
• Communities: Reddit r/Python, Stack Overflow, Python Discord
Key Tips for Success
1. Practice daily: Write code every day, even if just for 30 minutes
2. Build projects: Apply concepts to real-world problems
3. Read others' code: Study open-source Python projects
4. Learn debugging: Master debugging tools and techniques
5. Stay updated: Follow Python news and new features
6. Join community: Participate in Python forums and discussions
This comprehensive guide covers everything from basic Python syntax to advanced email automation
with machine learning. Each section builds upon the previous one, ensuring a solid foundation for Python
development. Remember that mastering programming is a journey - be patient, practice consistently,
and don't hesitate to experiment with the code examples!