欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

使用Python生成個性化的電子郵件簽名

 更新時間:2025年11月11日 08:34:37   作者:閑人編程  
在數(shù)字通信時代,電子郵件仍然是商務(wù)溝通和個人交流的重要工具,本文將詳細介紹如何使用Python構(gòu)建一個智能的個性化電子郵件簽名生成系統(tǒng),希望對大家有所幫助

1. 引言

在數(shù)字通信時代,電子郵件仍然是商務(wù)溝通和個人交流的重要工具。據(jù)統(tǒng)計,全球每天發(fā)送的電子郵件數(shù)量超過3000億封,而專業(yè)的電子郵件簽名不僅能夠提供必要的聯(lián)系信息,還能增強品牌形象、建立信任關(guān)系并促進業(yè)務(wù)增長。

一個精心設(shè)計的電子郵件簽名具有以下重要作用:

  • 專業(yè)形象:展示個人或公司的專業(yè)素養(yǎng)
  • 品牌推廣:強化品牌識別和一致性
  • 信息完整:提供全面的聯(lián)系方式和社交媒體鏈接
  • 營銷機會:包含推廣信息和行動號召
  • 法律合規(guī):滿足商業(yè)通信的法律要求

然而,手動創(chuàng)建和維護電子郵件簽名存在諸多挑戰(zhàn):

  • 格式不一致,影響專業(yè)形象
  • 更新聯(lián)系信息繁瑣且容易出錯
  • 難以在不同郵件客戶端保持顯示一致性
  • 缺乏個性化定制能力

本文將詳細介紹如何使用Python構(gòu)建一個智能的個性化電子郵件簽名生成系統(tǒng)。通過這個系統(tǒng),用戶可以快速生成美觀、專業(yè)且一致的電子郵件簽名,支持動態(tài)內(nèi)容、響應式設(shè)計和多平臺兼容。

2. 系統(tǒng)架構(gòu)設(shè)計

2.1 整體架構(gòu)概述

電子郵件簽名生成系統(tǒng)的核心架構(gòu)采用模塊化設(shè)計,確保代碼的可維護性和擴展性。

2.2 核心模塊設(shè)計

系統(tǒng)包含以下關(guān)鍵模塊:

  • 數(shù)據(jù)模型:定義簽名數(shù)據(jù)的結(jié)構(gòu)和驗證規(guī)則
  • 模板引擎:基于Jinja2的HTML模板渲染
  • 樣式處理器:管理CSS樣式和響應式設(shè)計
  • 圖像處理器:處理頭像、Logo等圖像資源
  • 輸出生成器:生成HTML、純文本等多種格式

2.3 技術(shù)選型理由

選擇Python作為開發(fā)語言的主要原因:

  • 豐富的庫生態(tài):擁有強大的HTML/CSS處理庫
  • 模板引擎成熟:Jinja2模板引擎功能強大
  • 圖像處理能力:Pillow庫提供專業(yè)的圖像處理功能
  • 跨平臺兼容:確保在不同操作系統(tǒng)上的一致性
  • 易于部署:簡單的部署和維護流程

3. 環(huán)境配置與依賴安裝

3.1 系統(tǒng)要求

  • Python 3.8+
  • 支持HTML5和CSS3的現(xiàn)代瀏覽器
  • 足夠的磁盤空間存儲模板和生成的文件

3.2 依賴包安裝

創(chuàng)建requirements.txt文件:

Jinja2==3.1.2
Pillow==10.0.0
python-dotenv==1.0.0
click==8.1.4
colorama==0.4.6
requests==2.28.2
beautifulsoup4==4.12.2
lxml==4.9.2
qrcode==7.4.2

安裝依賴:

pip install -r requirements.txt

3.3 項目結(jié)構(gòu)設(shè)計

email_signature_generator/
├── src/
│   ├── __init__.py
│   ├── models/
│   │   ├── __init__.py
│   │   ├── signature_data.py
│   │   └── validators.py
│   ├── generators/
│   │   ├── __init__.py
│   │   ├── html_generator.py
│   │   ├── text_generator.py
│   │   └── image_processor.py
│   ├── templates/
│   │   ├── html/
│   │   │   ├── corporate.html
│   │   │   ├── modern.html
│   │   │   └── minimal.html
│   │   └── css/
│   │       ├── corporate.css
│   │       ├── modern.css
│   │       └── minimal.css
│   ├── utils/
│   │   ├── __init__.py
│   │   ├── helpers.py
│   │   └── config.py
│   └── cli.py
├── tests/
├── examples/
├── docs/
├── requirements.txt
└── README.md

4. 數(shù)據(jù)模型設(shè)計

4.1 簽名數(shù)據(jù)模型

創(chuàng)建基礎(chǔ)數(shù)據(jù)模型來存儲簽名信息:

# src/models/signature_data.py
from dataclasses import dataclass, field
from typing import List, Optional, Dict, Any
from datetime import datetime
import re
from enum import Enum

class SocialPlatform(Enum):
    """支持的社交媒體平臺枚舉"""
    LINKEDIN = "linkedin"
    TWITTER = "twitter"
    FACEBOOK = "facebook"
    INSTAGRAM = "instagram"
    GITHUB = "github"
    WEBSITE = "website"
    YOUTUBE = "youtube"

class ThemeStyle(Enum):
    """主題樣式枚舉"""
    CORPORATE = "corporate"
    MODERN = "modern"
    MINIMAL = "minimal"
    CREATIVE = "creative"

@dataclass
class SocialMedia:
    """社交媒體鏈接數(shù)據(jù)類"""
    platform: SocialPlatform
    url: str
    username: Optional[str] = None
    
    @property
    def display_name(self) -> str:
        """獲取平臺顯示名稱"""
        platform_names = {
            SocialPlatform.LINKEDIN: "LinkedIn",
            SocialPlatform.TWITTER: "Twitter",
            SocialPlatform.FACEBOOK: "Facebook",
            SocialPlatform.INSTAGRAM: "Instagram",
            SocialPlatform.GITHUB: "GitHub",
            SocialPlatform.WEBSITE: "Website",
            SocialPlatform.YOUTUBE: "YouTube"
        }
        return platform_names.get(self.platform, self.platform.value)

@dataclass
class ContactInfo:
    """聯(lián)系信息數(shù)據(jù)類"""
    phone: Optional[str] = None
    mobile: Optional[str] = None
    email: Optional[str] = None
    address: Optional[str] = None
    website: Optional[str] = None
    
    def get_display_phone(self) -> Optional[str]:
        """格式化顯示電話號碼"""
        if not self.phone:
            return None
        # 簡單的電話號碼格式化
        cleaned = re.sub(r'\D', '', self.phone)
        if len(cleaned) == 10:
            return f"({cleaned[:3]}) {cleaned[3:6]}-{cleaned[6:]}"
        return self.phone

@dataclass
class SignatureData:
    """電子郵件簽名主數(shù)據(jù)類"""
    # 基本信息
    full_name: str
    job_title: str
    company: str
    department: Optional[str] = None
    
    # 聯(lián)系信息
    contact: ContactInfo = field(default_factory=ContactInfo)
    
    # 社交媒體
    social_media: List[SocialMedia] = field(default_factory=list)
    
    # 品牌信息
    logo_url: Optional[str] = None
    profile_picture_url: Optional[str] = None
    brand_color: Optional[str] = None
    secondary_color: Optional[str] = None
    
    # 營銷信息
    promotional_text: Optional[str] = None
    call_to_action: Optional[str] = None
    disclaimer: Optional[str] = None
    
    # 樣式配置
    theme: ThemeStyle = ThemeStyle.MODERN
    include_border: bool = True
    include_qr_code: bool = False
    qr_code_url: Optional[str] = None
    
    # 元數(shù)據(jù)
    created_at: datetime = field(default_factory=datetime.now)
    updated_at: datetime = field(default_factory=datetime.now)
    
    def add_social_media(self, platform: SocialPlatform, url: str, username: Optional[str] = None):
        """添加社交媒體鏈接"""
        social = SocialMedia(platform=platform, url=url, username=username)
        self.social_media.append(social)
    
    def remove_social_media(self, platform: SocialPlatform):
        """移除社交媒體鏈接"""
        self.social_media = [sm for sm in self.social_media if sm.platform != platform]
    
    def get_social_media_by_platform(self, platform: SocialPlatform) -> Optional[SocialMedia]:
        """根據(jù)平臺獲取社交媒體信息"""
        for social in self.social_media:
            if social.platform == platform:
                return social
        return None
    
    def to_dict(self) -> Dict[str, Any]:
        """轉(zhuǎn)換為字典格式"""
        return {
            'full_name': self.full_name,
            'job_title': self.job_title,
            'company': self.company,
            'department': self.department,
            'contact': {
                'phone': self.contact.phone,
                'mobile': self.contact.mobile,
                'email': self.contact.email,
                'address': self.contact.address,
                'website': self.contact.website
            },
            'social_media': [
                {
                    'platform': sm.platform.value,
                    'url': sm.url,
                    'username': sm.username
                } for sm in self.social_media
            ],
            'theme': self.theme.value,
            'brand_color': self.brand_color,
            'secondary_color': self.secondary_color,
            'promotional_text': self.promotional_text,
            'call_to_action': self.call_to_action,
            'disclaimer': self.disclaimer
        }
    
    @classmethod
    def from_dict(cls, data: Dict[str, Any]) -> 'SignatureData':
        """從字典創(chuàng)建實例"""
        contact_data = data.get('contact', {})
        contact = ContactInfo(
            phone=contact_data.get('phone'),
            mobile=contact_data.get('mobile'),
            email=contact_data.get('email'),
            address=contact_data.get('address'),
            website=contact_data.get('website')
        )
        
        signature = cls(
            full_name=data['full_name'],
            job_title=data['job_title'],
            company=data['company'],
            department=data.get('department'),
            contact=contact,
            brand_color=data.get('brand_color'),
            secondary_color=data.get('secondary_color'),
            promotional_text=data.get('promotional_text'),
            call_to_action=data.get('call_to_action'),
            disclaimer=data.get('disclaimer'),
            theme=ThemeStyle(data.get('theme', 'modern'))
        )
        
        # 添加社交媒體
        for sm_data in data.get('social_media', []):
            platform = SocialPlatform(sm_data['platform'])
            signature.add_social_media(platform, sm_data['url'], sm_data.get('username'))
        
        return signature

4.2 數(shù)據(jù)驗證器

創(chuàng)建數(shù)據(jù)驗證器確保輸入數(shù)據(jù)的有效性:

# src/models/validators.py
import re
from typing import Optional, Tuple
from urllib.parse import urlparse
from datetime import datetime

class SignatureValidator:
    """簽名數(shù)據(jù)驗證器"""
    
    @staticmethod
    def validate_email(email: str) -> Tuple[bool, str]:
        """驗證電子郵件地址"""
        if not email:
            return True, ""  # 空值視為有效
            
        pattern = r'^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$'
        if re.match(pattern, email):
            return True, ""
        return False, "無效的電子郵件格式"
    
    @staticmethod
    def validate_phone(phone: str) -> Tuple[bool, str]:
        """驗證電話號碼"""
        if not phone:
            return True, ""  # 空值視為有效
            
        # 移除所有非數(shù)字字符
        cleaned = re.sub(r'\D', '', phone)
        if 7 <= len(cleaned) <= 15:
            return True, ""
        return False, "電話號碼長度應在7-15位數(shù)字之間"
    
    @staticmethod
    def validate_url(url: str) -> Tuple[bool, str]:
        """驗證URL格式"""
        if not url:
            return True, ""  # 空值視為有效
            
        try:
            result = urlparse(url)
            if all([result.scheme, result.netloc]):
                return True, ""
            return False, "無效的URL格式"
        except:
            return False, "無效的URL格式"
    
    @staticmethod
    def validate_hex_color(color: str) -> Tuple[bool, str]:
        """驗證十六進制顏色值"""
        if not color:
            return True, ""  # 空值視為有效
            
        pattern = r'^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$'
        if re.match(pattern, color):
            return True, ""
        return False, "顏色格式應為 #RGB 或 #RRGGBB"
    
    @staticmethod
    def validate_full_name(name: str) -> Tuple[bool, str]:
        """驗證全名"""
        if not name or len(name.strip()) < 2:
            return False, "姓名不能少于2個字符"
        if len(name) > 100:
            return False, "姓名不能超過100個字符"
        return True, ""
    
    @staticmethod
    def validate_company(company: str) -> Tuple[bool, str]:
        """驗證公司名稱"""
        if not company or len(company.strip()) < 1:
            return False, "公司名稱不能為空"
        if len(company) > 200:
            return False, "公司名稱不能超過200個字符"
        return True, ""
    
    @staticmethod
    def validate_job_title(title: str) -> Tuple[bool, str]:
        """驗證職位名稱"""
        if not title or len(title.strip()) < 1:
            return False, "職位名稱不能為空"
        if len(title) > 100:
            return False, "職位名稱不能超過100個字符"
        return True, ""
    
    def validate_signature_data(self, data: 'SignatureData') -> Tuple[bool, Dict[str, str]]:
        """驗證完整的簽名數(shù)據(jù)"""
        errors = {}
        
        # 驗證基本信息
        is_valid, message = self.validate_full_name(data.full_name)
        if not is_valid:
            errors['full_name'] = message
            
        is_valid, message = self.validate_job_title(data.job_title)
        if not is_valid:
            errors['job_title'] = message
            
        is_valid, message = self.validate_company(data.company)
        if not is_valid:
            errors['company'] = message
        
        # 驗證聯(lián)系信息
        if data.contact.email:
            is_valid, message = self.validate_email(data.contact.email)
            if not is_valid:
                errors['email'] = message
                
        if data.contact.phone:
            is_valid, message = self.validate_phone(data.contact.phone)
            if not is_valid:
                errors['phone'] = message
                
        if data.contact.website:
            is_valid, message = self.validate_url(data.contact.website)
            if not is_valid:
                errors['website'] = message
        
        # 驗證社交媒體鏈接
        for social in data.social_media:
            is_valid, message = self.validate_url(social.url)
            if not is_valid:
                errors[f'social_{social.platform.value}'] = f"{social.display_name}: {message}"
        
        # 驗證品牌顏色
        if data.brand_color:
            is_valid, message = self.validate_hex_color(data.brand_color)
            if not is_valid:
                errors['brand_color'] = message
                
        if data.secondary_color:
            is_valid, message = self.validate_hex_color(data.secondary_color)
            if not is_valid:
                errors['secondary_color'] = message
        
        return len(errors) == 0, errors

5. HTML簽名生成器

5.1 基礎(chǔ)HTML生成器

創(chuàng)建核心的HTML簽名生成器:

# src/generators/html_generator.py
import os
import json
from typing import Dict, Any, Optional
from jinja2 import Environment, FileSystemLoader, Template
from ..models.signature_data import SignatureData, ThemeStyle
from .image_processor import ImageProcessor

class HTMLSignatureGenerator:
    """HTML電子郵件簽名生成器"""
    
    def __init__(self, templates_dir: str = None):
        """
        初始化生成器
        
        參數(shù):
            templates_dir: 模板目錄路徑
        """
        if templates_dir is None:
            # 默認模板目錄
            current_dir = os.path.dirname(os.path.abspath(__file__))
            templates_dir = os.path.join(current_dir, '..', 'templates', 'html')
        
        self.templates_dir = templates_dir
        self.env = Environment(
            loader=FileSystemLoader(templates_dir),
            trim_blocks=True,
            lstrip_blocks=True
        )
        self.image_processor = ImageProcessor()
        
        # 注冊自定義過濾器
        self.env.filters['escape_html'] = self._escape_html
        self.env.filters['format_phone'] = self._format_phone
        
    def _escape_html(self, text: str) -> str:
        """轉(zhuǎn)義HTML特殊字符"""
        if not text:
            return ""
        return (text.replace('&', '&amp;')
                  .replace('<', '&lt;')
                  .replace('>', '&gt;')
                  .replace('"', '&quot;')
                  .replace("'", '&#39;'))
    
    def _format_phone(self, phone: str) -> str:
        """格式化電話號碼顯示"""
        if not phone:
            return ""
        # 移除所有非數(shù)字字符
        cleaned = ''.join(filter(str.isdigit, phone))
        if len(cleaned) == 10:
            return f"({cleaned[:3]}) {cleaned[3:6]}-{cleaned[6:]}"
        return phone
    
    def _get_template_context(self, data: SignatureData) -> Dict[str, Any]:
        """構(gòu)建模板上下文數(shù)據(jù)"""
        # 處理品牌顏色
        brand_color = data.brand_color or '#2c5aa0'
        secondary_color = data.secondary_color or '#666666'
        
        # 處理社交媒體圖標
        social_icons = self._prepare_social_media(data.social_media)
        
        # 準備聯(lián)系信息
        contact_info = {
            'phone': data.contact.get_display_phone(),
            'mobile': data.contact.mobile,
            'email': data.contact.email,
            'address': data.contact.address,
            'website': data.contact.website
        }
        
        return {
            'data': data,
            'brand_color': brand_color,
            'secondary_color': secondary_color,
            'social_icons': social_icons,
            'contact_info': contact_info,
            'has_logo': bool(data.logo_url),
            'has_profile_picture': bool(data.profile_picture_url),
            'has_promotion': bool(data.promotional_text),
            'has_disclaimer': bool(data.disclaimer)
        }
    
    def _prepare_social_media(self, social_media_list) -> list:
        """準備社交媒體數(shù)據(jù)"""
        social_data = []
        
        for social in social_media_list:
            # 社交媒體平臺對應的圖標類和顏色
            platform_config = {
                'linkedin': {'icon': 'fab fa-linkedin', 'color': '#0077b5'},
                'twitter': {'icon': 'fab fa-twitter', 'color': '#1da1f2'},
                'facebook': {'icon': 'fab fa-facebook', 'color': '#1877f2'},
                'instagram': {'icon': 'fab fa-instagram', 'color': '#e4405f'},
                'github': {'icon': 'fab fa-github', 'color': '#333333'},
                'website': {'icon': 'fas fa-globe', 'color': '#666666'},
                'youtube': {'icon': 'fab fa-youtube', 'color': '#ff0000'}
            }
            
            config = platform_config.get(social.platform.value, {})
            social_data.append({
                'platform': social.platform.value,
                'display_name': social.display_name,
                'url': social.url,
                'username': social.username,
                'icon_class': config.get('icon', 'fas fa-link'),
                'color': config.get('color', '#666666')
            })
        
        return social_data
    
    def generate_signature(self, data: SignatureData, 
                          template_name: Optional[str] = None) -> str:
        """
        生成HTML簽名
        
        參數(shù):
            data: 簽名數(shù)據(jù)
            template_name: 模板名稱
            
        返回:
            HTML簽名字符串
        """
        if template_name is None:
            template_name = f"{data.theme.value}.html"
        
        # 驗證模板是否存在
        template_path = os.path.join(self.templates_dir, template_name)
        if not os.path.exists(template_path):
            raise FileNotFoundError(f"模板文件不存在: {template_path}")
        
        # 加載模板
        template = self.env.get_template(template_name)
        
        # 準備上下文數(shù)據(jù)
        context = self._get_template_context(data)
        
        # 渲染模板
        html_content = template.render(**context)
        
        # 清理和優(yōu)化HTML
        html_content = self._clean_html(html_content)
        
        return html_content
    
    def _clean_html(self, html: str) -> str:
        """清理和優(yōu)化HTML輸出"""
        # 移除多余的空格和換行
        html = ' '.join(html.split())
        
        # 確保HTML格式正確
        html = html.replace('> <', '><')  # 移除標簽間的空格
        
        return html
    
    def generate_with_css(self, data: SignatureData, 
                         template_name: Optional[str] = None) -> Dict[str, str]:
        """
        生成包含CSS的完整簽名
        
        參數(shù):
            data: 簽名數(shù)據(jù)
            template_name: 模板名稱
            
        返回:
            包含HTML和CSS的字典
        """
        html_content = self.generate_signature(data, template_name)
        
        # 加載對應的CSS文件
        css_content = self._load_css_template(data.theme)
        
        return {
            'html': html_content,
            'css': css_content,
            'inline_css': self._generate_inline_css(css_content)
        }
    
    def _load_css_template(self, theme: ThemeStyle) -> str:
        """加載CSS模板"""
        css_filename = f"{theme.value}.css"
        css_path = os.path.join(self.templates_dir, '..', 'css', css_filename)
        
        if os.path.exists(css_path):
            with open(css_path, 'r', encoding='utf-8') as f:
                return f.read()
        return ""
    
    def _generate_inline_css(self, css_content: str) -> str:
        """生成內(nèi)聯(lián)CSS樣式"""
        # 這里可以添加CSS內(nèi)聯(lián)化邏輯
        # 簡化版本,直接返回CSS內(nèi)容
        return f"<style>{css_content}</style>"
    
    def save_signature(self, data: SignatureData, output_path: str,
                      template_name: Optional[str] = None,
                      include_css: bool = True):
        """
        保存簽名到文件
        
        參數(shù):
            data: 簽名數(shù)據(jù)
            output_path: 輸出文件路徑
            template_name: 模板名稱
            include_css: 是否包含CSS
        """
        if include_css:
            result = self.generate_with_css(data, template_name)
            content = result['html'] + '\n' + result['inline_css']
        else:
            content = self.generate_signature(data, template_name)
        
        # 確保輸出目錄存在
        os.makedirs(os.path.dirname(output_path), exist_ok=True)
        
        with open(output_path, 'w', encoding='utf-8') as f:
            f.write(content)
        
        print(f"簽名已保存到: {output_path}")

5.2 圖像處理器

創(chuàng)建圖像處理模塊:

# src/generators/image_processor.py
import os
import requests
from PIL import Image, ImageDraw, ImageFont
import base64
from io import BytesIO
from typing import Optional, Tuple
import qrcode

class ImageProcessor:
    """圖像處理器"""
    
    def __init__(self, cache_dir: str = "image_cache"):
        """
        初始化圖像處理器
        
        參數(shù):
            cache_dir: 圖像緩存目錄
        """
        self.cache_dir = cache_dir
        os.makedirs(cache_dir, exist_ok=True)
    
    def download_image(self, url: str, max_size: Tuple[int, int] = (200, 200)) -> Optional[str]:
        """
        下載并調(diào)整圖像大小
        
        參數(shù):
            url: 圖像URL
            max_size: 最大尺寸 (寬, 高)
            
        返回:
            本地文件路徑或None
        """
        try:
            # 檢查緩存
            filename = self._get_filename_from_url(url)
            cache_path = os.path.join(self.cache_dir, filename)
            
            if os.path.exists(cache_path):
                return cache_path
            
            # 下載圖像
            response = requests.get(url, timeout=10)
            response.raise_for_status()
            
            # 打開并調(diào)整圖像
            image = Image.open(BytesIO(response.content))
            image.thumbnail(max_size, Image.Resampling.LANCZOS)
            
            # 保存為PNG格式
            image.save(cache_path, 'PNG')
            
            return cache_path
            
        except Exception as e:
            print(f"下載圖像失敗: {e}")
            return None
    
    def _get_filename_from_url(self, url: str) -> str:
        """從URL生成文件名"""
        import hashlib
        return hashlib.md5(url.encode()).hexdigest() + '.png'
    
    def image_to_base64(self, image_path: str) -> Optional[str]:
        """
        將圖像轉(zhuǎn)換為Base64編碼
        
        參數(shù):
            image_path: 圖像文件路徑
            
        返回:
            Base64編碼的字符串或None
        """
        try:
            with open(image_path, 'rb') as f:
                image_data = f.read()
                base64_encoded = base64.b64encode(image_data).decode('utf-8')
                return f"data:image/png;base64,{base64_encoded}"
        except Exception as e:
            print(f"圖像Base64編碼失敗: {e}")
            return None
    
    def create_qr_code(self, data: str, size: int = 100) -> Optional[str]:
        """
        生成QR碼
        
        參數(shù):
            data: QR碼數(shù)據(jù)
            size: 圖像尺寸
            
        返回:
            Base64編碼的QR碼圖像
        """
        try:
            qr = qrcode.QRCode(
                version=1,
                error_correction=qrcode.constants.ERROR_CORRECT_L,
                box_size=10,
                border=4,
            )
            qr.add_data(data)
            qr.make(fit=True)
            
            qr_image = qr.make_image(fill_color="black", back_color="white")
            qr_image = qr_image.resize((size, size))
            
            # 轉(zhuǎn)換為Base64
            buffer = BytesIO()
            qr_image.save(buffer, format='PNG')
            base64_encoded = base64.b64encode(buffer.getvalue()).decode('utf-8')
            
            return f"data:image/png;base64,{base64_encoded}"
            
        except Exception as e:
            print(f"生成QR碼失敗: {e}")
            return None
    
    def validate_image(self, image_path: str, max_size_mb: int = 2) -> Tuple[bool, str]:
        """
        驗證圖像文件
        
        參數(shù):
            image_path: 圖像文件路徑
            max_size_mb: 最大文件大小(MB)
            
        返回:
            (是否有效, 錯誤信息)
        """
        try:
            # 檢查文件大小
            file_size = os.path.getsize(image_path) / (1024 * 1024)  # MB
            if file_size > max_size_mb:
                return False, f"圖像文件過大 ({file_size:.1f}MB > {max_size_mb}MB)"
            
            # 檢查圖像格式
            with Image.open(image_path) as img:
                if img.format not in ['JPEG', 'PNG', 'GIF']:
                    return False, f"不支持的圖像格式: {img.format}"
                
                # 檢查圖像尺寸
                width, height = img.size
                if width > 1000 or height > 1000:
                    return False, f"圖像尺寸過大: {width}x{height}"
            
            return True, ""
            
        except Exception as e:
            return False, f"圖像驗證失敗: {str(e)}"

6. 模板系統(tǒng)設(shè)計

6.1 企業(yè)風格模板

創(chuàng)建企業(yè)風格HTML模板:

<!-- src/templates/html/corporate.html -->
<table cellpadding="0" cellspacing="0" border="0" width="600" style="border-collapse: collapse; font-family: Arial, sans-serif; font-size: 12px; line-height: 1.4; color: #333333; border: {% if data.include_border %}1px solid #dddddd{% else %}none{% endif %};">
    <tr>
        {% if data.logo_url %}
        <td width="100" valign="top" style="padding: 15px;">
            <img src="{{ data.logo_url }}" alt="{{ data.company }} Logo" width="80" style="display: block; border: none;" />
        </td>
        {% endif %}
        
        <td valign="top" style="padding: 15px; {% if not data.logo_url %}padding-left: 0;{% endif %}">
            <!-- 姓名和職位 -->
            <table cellpadding="0" cellspacing="0" border="0">
                <tr>
                    <td style="padding-bottom: 5px;">
                        <strong style="font-size: 14px; color: {{ brand_color }};">{{ data.full_name|escape_html }}</strong>
                    </td>
                </tr>
                <tr>
                    <td style="padding-bottom: 8px;">
                        <span style="font-size: 12px; color: {{ secondary_color }};">{{ data.job_title|escape_html }}</span>
                        {% if data.department %}
                        <span style="color: #999999;"> | </span>
                        <span style="font-size: 12px; color: #999999;">{{ data.department|escape_html }}</span>
                        {% endif %}
                    </td>
                </tr>
            </table>
            
            <!-- 公司信息 -->
            <table cellpadding="0" cellspacing="0" border="0" style="margin-bottom: 10px;">
                <tr>
                    <td style="font-size: 12px; color: {{ brand_color }}; font-weight: bold;">
                        {{ data.company|escape_html }}
                    </td>
                </tr>
            </table>
            
            <!-- 聯(lián)系信息 -->
            <table cellpadding="0" cellspacing="0" border="0" style="margin-bottom: 10px;">
                {% if contact_info.phone %}
                <tr>
                    <td width="20" valign="top">??</td>
                    <td style="padding-bottom: 2px;">
                        <span style="font-size: 11px;">電話: {{ contact_info.phone|format_phone }}</span>
                    </td>
                </tr>
                {% endif %}
                
                {% if contact_info.mobile %}
                <tr>
                    <td width="20" valign="top">??</td>
                    <td style="padding-bottom: 2px;">
                        <span style="font-size: 11px;">手機: {{ contact_info.mobile|format_phone }}</span>
                    </td>
                </tr>
                {% endif %}
                
                {% if contact_info.email %}
                <tr>
                    <td width="20" valign="top">??</td>
                    <td style="padding-bottom: 2px;">
                        <a href="mailto:{{ contact_info.email }}" rel="external nofollow"  rel="external nofollow"  style="font-size: 11px; color: {{ brand_color }}; text-decoration: none;">
                            {{ contact_info.email|escape_html }}
                        </a>
                    </td>
                </tr>
                {% endif %}
                
                {% if contact_info.website %}
                <tr>
                    <td width="20" valign="top">??</td>
                    <td style="padding-bottom: 2px;">
                        <a href="{{ contact_info.website }}" rel="external nofollow"  rel="external nofollow"  style="font-size: 11px; color: {{ brand_color }}; text-decoration: none;">
                            {{ contact_info.website|escape_html }}
                        </a>
                    </td>
                </tr>
                {% endif %}
            </table>
            
            <!-- 社交媒體 -->
            {% if social_icons %}
            <table cellpadding="0" cellspacing="0" border="0" style="margin-bottom: 10px;">
                <tr>
                    <td style="padding-bottom: 5px;">
                        <span style="font-size: 11px; color: #999999;">關(guān)注我們:</span>
                    </td>
                </tr>
                <tr>
                    <td>
                        {% for social in social_icons %}
                        <a href="{{ social.url }}" rel="external nofollow"  rel="external nofollow"  style="text-decoration: none; margin-right: 8px; display: inline-block;">
                            <span style="color: {{ social.color }}; font-size: 14px;">[{{ social.display_name }}]</span>
                        </a>
                        {% endfor %}
                    </td>
                </tr>
            </table>
            {% endif %}
            
            <!-- 推廣信息 -->
            {% if data.promotional_text %}
            <table cellpadding="0" cellspacing="0" border="0" style="margin-bottom: 10px; background-color: #f8f9fa; padding: 8px; border-left: 3px solid {{ brand_color }};">
                <tr>
                    <td>
                        <span style="font-size: 11px; color: #666666; font-style: italic;">
                            {{ data.promotional_text|escape_html }}
                        </span>
                    </td>
                </tr>
            </table>
            {% endif %}
            
            <!-- 免責聲明 -->
            {% if data.disclaimer %}
            <table cellpadding="0" cellspacing="0" border="0">
                <tr>
                    <td>
                        <span style="font-size: 9px; color: #999999; line-height: 1.2;">
                            {{ data.disclaimer|escape_html }}
                        </span>
                    </td>
                </tr>
            </table>
            {% endif %}
        </td>
        
        <!-- QR碼 -->
        {% if data.include_qr_code and data.qr_code_url %}
        <td width="80" valign="middle" align="center" style="padding: 15px;">
            <img src="{{ data.qr_code_url }}" alt="QR Code" width="60" style="display: block; border: none;" />
            <span style="font-size: 9px; color: #999999;">掃描聯(lián)系我</span>
        </td>
        {% endif %}
    </tr>
</table>

6.2 現(xiàn)代風格模板

創(chuàng)建現(xiàn)代風格HTML模板:

<!-- src/templates/html/modern.html -->
<table cellpadding="0" cellspacing="0" border="0" width="100%" style="max-width: 550px; border-collapse: collapse; font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; font-size: 13px; line-height: 1.5; color: #444444; background: linear-gradient(135deg, #ffffff 0%, #f8f9fa 100%); border-radius: 8px; overflow: hidden; box-shadow: 0 2px 10px rgba(0,0,0,0.1);">
    <tr>
        <!-- 左側(cè)品牌區(qū)域 -->
        <td width="30%" valign="top" style="background: {{ brand_color }}; padding: 20px; color: white;">
            {% if data.logo_url %}
            <div style="margin-bottom: 15px;">
                <img src="{{ data.logo_url }}" alt="{{ data.company }} Logo" width="60" style="display: block; border: none; background: white; padding: 5px; border-radius: 4px;" />
            </div>
            {% endif %}
            
            <div style="font-size: 16px; font-weight: bold; margin-bottom: 5px;">
                {{ data.full_name|escape_html }}
            </div>
            
            <div style="font-size: 12px; opacity: 0.9;">
                {{ data.job_title|escape_html }}
            </div>
            
            {% if data.department %}
            <div style="font-size: 11px; opacity: 0.8; margin-top: 3px;">
                {{ data.department|escape_html }}
            </div>
            {% endif %}
        </td>
        
        <!-- 右側(cè)內(nèi)容區(qū)域 -->
        <td valign="top" style="padding: 20px;">
            <!-- 公司名稱 -->
            <div style="font-size: 14px; font-weight: bold; color: {{ brand_color }}; margin-bottom: 15px;">
                {{ data.company|escape_html }}
            </div>
            
            <!-- 聯(lián)系信息 -->
            <table cellpadding="0" cellspacing="0" border="0" width="100%" style="margin-bottom: 15px;">
                {% if contact_info.phone %}
                <tr>
                    <td width="20" valign="top" style="padding-bottom: 6px;">
                        <span style="color: {{ brand_color }};">●</span>
                    </td>
                    <td style="padding-bottom: 6px;">
                        <span style="font-size: 12px;">{{ contact_info.phone|format_phone }}</span>
                    </td>
                </tr>
                {% endif %}
                
                {% if contact_info.email %}
                <tr>
                    <td width="20" valign="top" style="padding-bottom: 6px;">
                        <span style="color: {{ brand_color }};">●</span>
                    </td>
                    <td style="padding-bottom: 6px;">
                        <a href="mailto:{{ contact_info.email }}" rel="external nofollow"  rel="external nofollow"  style="font-size: 12px; color: {{ brand_color }}; text-decoration: none;">
                            {{ contact_info.email|escape_html }}
                        </a>
                    </td>
                </tr>
                {% endif %}
                
                {% if contact_info.website %}
                <tr>
                    <td width="20" valign="top" style="padding-bottom: 6px;">
                        <span style="color: {{ brand_color }};">●</span>
                    </td>
                    <td style="padding-bottom: 6px;">
                        <a href="{{ contact_info.website }}" rel="external nofollow"  rel="external nofollow"  style="font-size: 12px; color: {{ brand_color }}; text-decoration: none;">
                            {{ contact_info.website|escape_html }}
                        </a>
                    </td>
                </tr>
                {% endif %}
            </table>
            
            <!-- 社交媒體 -->
            {% if social_icons %}
            <div style="margin-bottom: 15px;">
                <table cellpadding="0" cellspacing="0" border="0">
                    <tr>
                        {% for social in social_icons %}
                        <td style="padding-right: 8px;">
                            <a href="{{ social.url }}" rel="external nofollow"  rel="external nofollow"  style="display: inline-block; width: 24px; height: 24px; background-color: {{ social.color }}; border-radius: 50%; text-align: center; line-height: 24px; text-decoration: none; color: white; font-size: 12px;">
                                {{ social.display_name|first|upper }}
                            </a>
                        </td>
                        {% endfor %}
                    </tr>
                </table>
            </div>
            {% endif %}
            
            <!-- 行動號召 -->
            {% if data.call_to_action %}
            <div style="background-color: {{ brand_color }}; color: white; padding: 8px 12px; border-radius: 4px; text-align: center; margin-bottom: 10px;">
                <span style="font-size: 11px; font-weight: bold;">
                    {{ data.call_to_action|escape_html }}
                </span>
            </div>
            {% endif %}
        </td>
    </tr>
    
    <!-- 底部區(qū)域 -->
    {% if data.promotional_text or data.disclaimer %}
    <tr>
        <td colspan="2" style="background-color: #f8f9fa; padding: 15px 20px; border-top: 1px solid #e9ecef;">
            {% if data.promotional_text %}
            <div style="font-size: 11px; color: #666666; margin-bottom: 8px;">
                ? {{ data.promotional_text|escape_html }}
            </div>
            {% endif %}
            
            {% if data.disclaimer %}
            <div style="font-size: 9px; color: #999999; line-height: 1.3;">
                {{ data.disclaimer|escape_html }}
            </div>
            {% endif %}
        </td>
    </tr>
    {% endif %}
</table>

6.3 CSS樣式文件

創(chuàng)建對應的CSS樣式文件:

/* src/templates/css/corporate.css */
.corporate-signature {
    font-family: Arial, sans-serif;
    font-size: 12px;
    line-height: 1.4;
    color: #333333;
    border-collapse: collapse;
}

.corporate-signature a {
    color: #2c5aa0;
    text-decoration: none;
}

.corporate-signature a:hover {
    text-decoration: underline;
}

.corporate-signature .brand-color {
    color: #2c5aa0;
}

.corporate-signature .secondary-color {
    color: #666666;
}

.corporate-signature .promotional-box {
    background-color: #f8f9fa;
    padding: 8px;
    border-left: 3px solid #2c5aa0;
    font-style: italic;
}

.corporate-signature .disclaimer {
    font-size: 9px;
    color: #999999;
    line-height: 1.2;
}
/* src/templates/css/modern.css */
.modern-signature {
    font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
    font-size: 13px;
    line-height: 1.5;
    color: #444444;
    border-collapse: collapse;
    border-radius: 8px;
    overflow: hidden;
    box-shadow: 0 2px 10px rgba(0,0,0,0.1);
}

.modern-signature a {
    text-decoration: none;
}

.modern-signature .brand-section {
    background: linear-gradient(135deg, #2c5aa0 0%, #1e3a8a 100%);
    color: white;
}

.modern-signature .social-icon {
    display: inline-block;
    width: 24px;
    height: 24px;
    border-radius: 50%;
    text-align: center;
    line-height: 24px;
    color: white;
    font-size: 12px;
}

.modern-signature .cta-button {
    background-color: #2c5aa0;
    color: white;
    padding: 8px 12px;
    border-radius: 4px;
    text-align: center;
    font-weight: bold;
}

.modern-signature .footer-section {
    background-color: #f8f9fa;
    border-top: 1px solid #e9ecef;
}

7. 純文本簽名生成器

創(chuàng)建純文本簽名生成器,確保在不支持HTML的客戶端中正常顯示:

# src/generators/text_generator.py
from ..models.signature_data import SignatureData
from typing import List

class TextSignatureGenerator:
    """純文本電子郵件簽名生成器"""
    
    def __init__(self, line_width: int = 70):
        """
        初始化生成器
        
        參數(shù):
            line_width: 行寬(字符數(shù))
        """
        self.line_width = line_width
    
    def generate_signature(self, data: SignatureData) -> str:
        """
        生成純文本簽名
        
        參數(shù):
            data: 簽名數(shù)據(jù)
            
        返回:
            純文本簽名字符串
        """
        lines = []
        
        # 分隔線
        lines.append("=" * self.line_width)
        
        # 姓名和職位
        name_line = data.full_name
        if data.job_title:
            name_line += f" | {data.job_title}"
        lines.append(name_line)
        
        # 公司和部門
        company_line = data.company
        if data.department:
            company_line += f" | {data.department}"
        lines.append(company_line)
        
        lines.append("")  # 空行
        
        # 聯(lián)系信息
        if data.contact.phone:
            lines.append(f"電話: {data.contact.get_display_phone()}")
        
        if data.contact.mobile:
            lines.append(f"手機: {data.contact.mobile}")
        
        if data.contact.email:
            lines.append(f"郵箱: {data.contact.email}")
        
        if data.contact.website:
            lines.append(f"網(wǎng)站: {data.contact.website}")
        
        if data.contact.address:
            # 地址可能較長,需要換行處理
            address_lines = self._wrap_text(f"地址: {data.contact.address}", self.line_width)
            lines.extend(address_lines)
        
        # 社交媒體
        if data.social_media:
            lines.append("")  # 空行
            lines.append("關(guān)注我:")
            for social in data.social_media:
                lines.append(f"  {social.display_name}: {social.url}")
        
        # 推廣信息
        if data.promotional_text:
            lines.append("")  # 空行
            promo_lines = self._wrap_text(f"? {data.promotional_text}", self.line_width)
            lines.extend(promo_lines)
        
        # 行動號召
        if data.call_to_action:
            lines.append("")  # 空行
            cta_lines = self._wrap_text(f"?? {data.call_to_action}", self.line_width)
            lines.extend(cta_lines)
        
        # 免責聲明
        if data.disclaimer:
            lines.append("")  # 空行
            disclaimer_lines = self._wrap_text(data.disclaimer, self.line_width)
            lines.extend(disclaimer_lines)
        
        # 結(jié)束分隔線
        lines.append("=" * self.line_width)
        
        return "\n".join(lines)
    
    def _wrap_text(self, text: str, width: int) -> List[str]:
        """
        文本換行處理
        
        參數(shù):
            text: 原始文本
            width: 行寬
            
        返回:
            換行后的文本列表
        """
        words = text.split()
        lines = []
        current_line = []
        current_length = 0
        
        for word in words:
            # 計算添加這個詞后的行長度
            word_length = len(word)
            if current_line:
                # 加上空格的長度
                word_length += 1
            
            if current_length + word_length <= width:
                current_line.append(word)
                current_length += word_length
            else:
                # 開始新行
                if current_line:
                    lines.append(' '.join(current_line))
                current_line = [word]
                current_length = len(word)
        
        # 添加最后一行
        if current_line:
            lines.append(' '.join(current_line))
        
        return lines
    
    def save_signature(self, data: SignatureData, output_path: str):
        """
        保存純文本簽名到文件
        
        參數(shù):
            data: 簽名數(shù)據(jù)
            output_path: 輸出文件路徑
        """
        text_content = self.generate_signature(data)
        
        # 確保輸出目錄存在
        import os
        os.makedirs(os.path.dirname(output_path), exist_ok=True)
        
        with open(output_path, 'w', encoding='utf-8') as f:
            f.write(text_content)
        
        print(f"純文本簽名已保存到: {output_path}")

8. 命令行界面

創(chuàng)建用戶友好的命令行界面:

# src/cli.py
import click
import json
import os
from typing import Dict, Any
from .models.signature_data import SignatureData, ThemeStyle, SocialPlatform, ContactInfo
from .models.validators import SignatureValidator
from .generators.html_generator import HTMLSignatureGenerator
from .generators.text_generator import TextSignatureGenerator

@click.group()
def cli():
    """個性化電子郵件簽名生成工具"""
    pass

@cli.command()
@click.option('--name', prompt='姓名', help='您的全名')
@click.option('--title', prompt='職位', help='您的職位名稱')
@click.option('--company', prompt='公司', help='公司名稱')
@click.option('--department', help='部門名稱')
@click.option('--email', prompt='電子郵件', help='電子郵件地址')
@click.option('--phone', help='電話號碼')
@click.option('--website', help='個人或公司網(wǎng)站')
@click.option('--theme', type=click.Choice(['corporate', 'modern', 'minimal']), 
              default='modern', help='簽名主題風格')
@click.option('--output', '-o', default='signature.html', help='輸出文件路徑')
@click.option('--format', '-f', type=click.Choice(['html', 'text', 'both']), 
              default='html', help='輸出格式')
def create(name, title, company, department, email, phone, website, theme, output, format):
    """創(chuàng)建新的電子郵件簽名"""
    
    # 創(chuàng)建聯(lián)系信息
    contact = ContactInfo(
        email=email,
        phone=phone,
        website=website
    )
    
    # 創(chuàng)建簽名數(shù)據(jù)
    signature_data = SignatureData(
        full_name=name,
        job_title=title,
        company=company,
        department=department,
        contact=contact,
        theme=ThemeStyle(theme)
    )
    
    # 驗證數(shù)據(jù)
    validator = SignatureValidator()
    is_valid, errors = validator.validate_signature_data(signature_data)
    
    if not is_valid:
        click.echo("數(shù)據(jù)驗證失敗:")
        for field, error in errors.items():
            click.echo(f"  {field}: {error}")
        return
    
    # 生成簽名
    if format in ['html', 'both']:
        html_generator = HTMLSignatureGenerator()
        html_output = output if format == 'html' else output.replace('.html', '_html.html')
        html_generator.save_signature(signature_data, html_output)
    
    if format in ['text', 'both']:
        text_generator = TextSignatureGenerator()
        text_output = output if format == 'text' else output.replace('.html', '_text.txt')
        text_generator.save_signature(signature_data, text_output)
    
    click.echo("簽名創(chuàng)建成功!")

@cli.command()
@click.argument('config_file', type=click.File('r'))
@click.option('--output', '-o', required=True, help='輸出文件路徑')
@click.option('--format', '-f', type=click.Choice(['html', 'text', 'both']), 
              default='html', help='輸出格式')
def from_config(config_file, output, format):
    """從配置文件創(chuàng)建簽名"""
    
    try:
        config_data = json.load(config_file)
        signature_data = SignatureData.from_dict(config_data)
        
        # 驗證數(shù)據(jù)
        validator = SignatureValidator()
        is_valid, errors = validator.validate_signature_data(signature_data)
        
        if not is_valid:
            click.echo("配置數(shù)據(jù)驗證失敗:")
            for field, error in errors.items():
                click.echo(f"  {field}: {error}")
            return
        
        # 生成簽名
        if format in ['html', 'both']:
            html_generator = HTMLSignatureGenerator()
            html_output = output if format == 'html' else output.replace('.html', '_html.html')
            html_generator.save_signature(signature_data, html_output)
        
        if format in ['text', 'both']:
            text_generator = TextSignatureGenerator()
            text_output = output if format == 'text' else output.replace('.html', '_text.txt')
            text_generator.save_signature(signature_data, text_output)
        
        click.echo("簽名創(chuàng)建成功!")
        
    except json.JSONDecodeError:
        click.echo("配置文件格式錯誤,請檢查JSON格式")
    except Exception as e:
        click.echo(f"處理配置文件時出錯: {e}")

@cli.command()
@click.option('--name', help='姓名')
@click.option('--title', help='職位')
@click.option('--company', help='公司')
@click.option('--output', default='signature_config.json', help='輸出配置文件路徑')
def create_config(name, title, company, output):
    """創(chuàng)建簽名配置文件模板"""
    
    config_template = {
        "full_name": name or "張三",
        "job_title": title or "軟件工程師",
        "company": company or "示例公司",
        "department": "技術(shù)部",
        "contact": {
            "phone": "+86-10-12345678",
            "mobile": "+86-138-0000-0000",
            "email": "zhangsan@example.com",
            "address": "北京市朝陽區(qū)示例街道123號",
            "website": "https://www.example.com"
        },
        "social_media": [
            {
                "platform": "linkedin",
                "url": "https://linkedin.com/in/zhangsan",
                "username": "zhangsan"
            },
            {
                "platform": "github",
                "url": "https://github.com/zhangsan",
                "username": "zhangsan"
            }
        ],
        "theme": "modern",
        "brand_color": "#2c5aa0",
        "secondary_color": "#666666",
        "promotional_text": "歡迎了解我們的最新產(chǎn)品和服務(wù)!",
        "call_to_action": "立即預約演示",
        "disclaimer": "本郵件及其附件包含保密信息,僅限指定收件人使用。"
    }
    
    with open(output, 'w', encoding='utf-8') as f:
        json.dump(config_template, f, ensure_ascii=False, indent=2)
    
    click.echo(f"配置文件模板已創(chuàng)建: {output}")
    click.echo("請編輯此文件后使用 'from-config' 命令生成簽名")

@cli.command()
@click.argument('input_file')
@click.option('--theme', type=click.Choice(['corporate', 'modern', 'minimal']), 
              help='主題風格')
@click.option('--output', '-o', help='輸出文件路徑')
def preview(input_file, theme, output):
    """預覽簽名效果"""
    
    try:
        with open(input_file, 'r', encoding='utf-8') as f:
            if input_file.endswith('.json'):
                config_data = json.load(f)
                signature_data = SignatureData.from_dict(config_data)
            else:
                # 這里可以添加其他格式的支持
                raise click.ClickException("不支持的輸入文件格式")
        
        if theme:
            signature_data.theme = ThemeStyle(theme)
        
        # 生成HTML預覽
        html_generator = HTMLSignatureGenerator()
        html_content = html_generator.generate_signature(signature_data)
        
        if output:
            html_generator.save_signature(signature_data, output)
            click.echo(f"預覽文件已保存: {output}")
        else:
            # 在控制臺顯示HTML代碼
            click.echo("生成的HTML簽名:")
            click.echo("=" * 80)
            click.echo(html_content)
            click.echo("=" * 80)
            click.echo("請將上述代碼復制到您的電子郵件客戶端中使用")
            
    except Exception as e:
        click.echo(f"預覽失敗: {e}")

if __name__ == '__main__':
    cli()

9. 完整示例和使用方法

9.1 基本使用示例

創(chuàng)建使用示例文件:

# examples/basic_usage.py
import os
import sys
sys.path.append(os.path.join(os.path.dirname(__file__), '..'))

from src.models.signature_data import SignatureData, ContactInfo, SocialPlatform, ThemeStyle
from src.generators.html_generator import HTMLSignatureGenerator
from src.generators.text_generator import TextSignatureGenerator

def create_basic_signature():
    """創(chuàng)建基礎(chǔ)簽名示例"""
    
    # 創(chuàng)建聯(lián)系信息
    contact = ContactInfo(
        phone="+86-10-12345678",
        mobile="+86-138-0000-0000",
        email="zhangsan@example.com",
        website="https://www.example.com",
        address="北京市朝陽區(qū)示例街道123號"
    )
    
    # 創(chuàng)建簽名數(shù)據(jù)
    signature_data = SignatureData(
        full_name="張三",
        job_title="高級軟件工程師",
        company="創(chuàng)新科技有限公司",
        department="技術(shù)研發(fā)部",
        contact=contact,
        brand_color="#2c5aa0",
        secondary_color="#666666",
        theme=ThemeStyle.MODERN,
        promotional_text="專注于人工智能和云計算解決方案",
        call_to_action="查看我們的最新產(chǎn)品",
        disclaimer="本郵件及其附件包含保密信息,僅限指定收件人使用。"
    )
    
    # 添加社交媒體
    signature_data.add_social_media(
        SocialPlatform.LINKEDIN, 
        "https://linkedin.com/in/zhangsan",
        "zhangsan"
    )
    signature_data.add_social_media(
        SocialPlatform.GITHUB,
        "https://github.com/zhangsan",
        "zhangsan"
    )
    signature_data.add_social_media(
        SocialPlatform.WEBSITE,
        "https://www.zhangsan.com"
    )
    
    return signature_data

def generate_all_formats():
    """生成所有格式的簽名"""
    signature_data = create_basic_signature()
    
    # 生成HTML簽名
    html_generator = HTMLSignatureGenerator()
    html_signature = html_generator.generate_signature(signature_data)
    
    # 生成純文本簽名
    text_generator = TextSignatureGenerator()
    text_signature = text_generator.generate_signature(signature_data)
    
    # 保存文件
    with open('examples/output/signature.html', 'w', encoding='utf-8') as f:
        f.write(html_signature)
    
    with open('examples/output/signature.txt', 'w', encoding='utf-8') as f:
        f.write(text_signature)
    
    print("HTML簽名已保存: examples/output/signature.html")
    print("純文本簽名已保存: examples/output/signature.txt")
    
    return html_signature, text_signature

if __name__ == '__main__':
    # 確保輸出目錄存在
    os.makedirs('examples/output', exist_ok=True)
    
    html, text = generate_all_formats()
    
    print("\n生成的HTML簽名預覽:")
    print("=" * 50)
    print(html[:500] + "..." if len(html) > 500 else html)
    
    print("\n生成的純文本簽名:")
    print("=" * 50)
    print(text)

9.2 配置文件示例

創(chuàng)建配置文件示例:

{
  "full_name": "李四",
  "job_title": "產(chǎn)品經(jīng)理",
  "company": "數(shù)字創(chuàng)新有限公司",
  "department": "產(chǎn)品部",
  "contact": {
    "phone": "+86-21-87654321",
    "mobile": "+86-139-1111-2222",
    "email": "lisi@digital-innovations.com",
    "address": "上海市浦東新區(qū)創(chuàng)新路456號",
    "website": "https://www.digital-innovations.com"
  },
  "social_media": [
    {
      "platform": "linkedin",
      "url": "https://linkedin.com/in/lisi",
      "username": "lisi"
    },
    {
      "platform": "twitter",
      "url": "https://twitter.com/lisi",
      "username": "lisi"
    },
    {
      "platform": "website",
      "url": "https://www.lisi.blog"
    }
  ],
  "theme": "corporate",
  "brand_color": "#d35400",
  "secondary_color": "#7f8c8d",
  "promotional_text": "我們致力于打造用戶體驗卓越的數(shù)字產(chǎn)品",
  "call_to_action": "立即體驗我們的產(chǎn)品演示",
  "disclaimer": "本郵件內(nèi)容僅供參考,不構(gòu)成任何承諾或保證。",
  "include_border": true,
  "include_qr_code": true,
  "qr_code_url": "https://www.digital-innovations.com/contact"
}

10. 測試和驗證

單元測試

創(chuàng)建基礎(chǔ)測試用例:

# tests/test_signature_generator.py
import unittest
import os
import sys
sys.path.append(os.path.join(os.path.dirname(__file__), '..'))

from src.models.signature_data import SignatureData, ContactInfo, SocialPlatform
from src.models.validators import SignatureValidator
from src.generators.html_generator import HTMLSignatureGenerator
from src.generators.text_generator import TextSignatureGenerator

class TestSignatureGenerator(unittest.TestCase):
    
    def setUp(self):
        """測試前置設(shè)置"""
        self.contact = ContactInfo(
            phone="+86-10-12345678",
            email="test@example.com",
            website="https://www.example.com"
        )
        
        self.signature_data = SignatureData(
            full_name="測試用戶",
            job_title="測試工程師",
            company="測試公司",
            contact=self.contact
        )
        
        self.validator = SignatureValidator()
        self.html_generator = HTMLSignatureGenerator()
        self.text_generator = TextSignatureGenerator()
    
    def test_valid_signature_data(self):
        """測試有效簽名數(shù)據(jù)驗證"""
        is_valid, errors = self.validator.validate_signature_data(self.signature_data)
        self.assertTrue(is_valid)
        self.assertEqual(len(errors), 0)
    
    def test_invalid_email(self):
        """測試無效電子郵件驗證"""
        self.signature_data.contact.email = "invalid-email"
        is_valid, errors = self.validator.validate_signature_data(self.signature_data)
        self.assertFalse(is_valid)
        self.assertIn('email', errors)
    
    def test_html_generation(self):
        """測試HTML生成"""
        html_content = self.html_generator.generate_signature(self.signature_data)
        self.assertIsInstance(html_content, str)
        self.assertGreater(len(html_content), 0)
        self.assertIn('測試用戶', html_content)
        self.assertIn('測試公司', html_content)
    
    def test_text_generation(self):
        """測試純文本生成"""
        text_content = self.text_generator.generate_signature(self.signature_data)
        self.assertIsInstance(text_content, str)
        self.assertGreater(len(text_content), 0)
        self.assertIn('測試用戶', text_content)
        self.assertIn('測試公司', text_content)
    
    def test_social_media_addition(self):
        """測試社交媒體添加"""
        initial_count = len(self.signature_data.social_media)
        self.signature_data.add_social_media(SocialPlatform.LINKEDIN, "https://linkedin.com/in/test")
        self.assertEqual(len(self.signature_data.social_media), initial_count + 1)
    
    def test_phone_formatting(self):
        """測試電話號碼格式化"""
        formatted = self.signature_data.contact.get_display_phone()
        self.assertIsNotNone(formatted)
        # 檢查是否包含格式化的電話號碼元素

if __name__ == '__main__':
    unittest.main()

11. 部署和使用說明

11.1 安裝和使用

安裝依賴

pip install -r requirements.txt

基本使用

# 交互式創(chuàng)建簽名
python -m src.cli create

# 使用配置文件創(chuàng)建簽名
python -m src.cli from-config config.json --output signature.html

# 創(chuàng)建配置文件模板
python -m src.cli create-config --output my_config.json

# 預覽簽名
python -m src.cli preview my_config.json

在Python代碼中使用

from src.models.signature_data import SignatureData, ContactInfo
from src.generators.html_generator import HTMLSignatureGenerator

# 創(chuàng)建簽名數(shù)據(jù)
contact = ContactInfo(email="user@example.com", phone="+1234567890")
data = SignatureData("張三", "工程師", "科技公司", contact=contact)

# 生成HTML簽名
generator = HTMLSignatureGenerator()
signature = generator.generate_signature(data)

11.2 最佳實踐

圖像優(yōu)化

  • 使用小于200KB的圖像文件
  • 推薦使用PNG格式以獲得更好的透明度支持
  • 確保圖像尺寸適當(建議100-200像素寬度)

顏色選擇

  • 使用品牌顏色保持一致
  • 確保足夠的顏色對比度以便閱讀
  • 考慮色盲用戶的體驗

響應式設(shè)計

  • 測試在不同郵件客戶端中的顯示效果
  • 使用表格布局確保兼容性
  • 提供純文本備用版本

可訪問性

  • 為圖像提供alt文本
  • 使用語義化的HTML結(jié)構(gòu)
  • 確保鍵盤導航友好

12. 總結(jié)

本文詳細介紹了一個完整的個性化電子郵件簽名生成系統(tǒng)的設(shè)計和實現(xiàn)。通過這個系統(tǒng),用戶可以:

  • 快速創(chuàng)建專業(yè)簽名:通過簡單的命令行界面或配置文件快速生成簽名
  • 多格式支持:同時生成HTML和純文本格式,確保兼容性
  • 高度可定制:支持多種主題風格、顏色配置和布局選項
  • 數(shù)據(jù)驗證:確保輸入數(shù)據(jù)的有效性和一致性
  • 社交媒體集成:輕松添加和管理社交媒體鏈接

這個系統(tǒng)的核心優(yōu)勢在于其靈活性和易用性。無論是個人用戶還是企業(yè)管理員,都可以通過這個工具快速創(chuàng)建和維護專業(yè)的電子郵件簽名,提升溝通的專業(yè)性和效率。

通過模塊化的設(shè)計和良好的代碼結(jié)構(gòu),這個系統(tǒng)還具有良好的可擴展性,可以輕松添加新的模板主題、輸出格式或集成其他功能。

以上就是使用Python生成個性化的電子郵件簽名的詳細內(nèi)容,更多關(guān)于Python生成電子郵件簽名的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • Python DataFrame設(shè)置/更改列表字段/元素類型的方法

    Python DataFrame設(shè)置/更改列表字段/元素類型的方法

    今天小編就為大家分享一篇Python DataFrame設(shè)置/更改列表字段/元素類型的方法,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2018-06-06
  • Python QListView教程的實現(xiàn)

    Python QListView教程的實現(xiàn)

    QListView是PyQt中的一個強大控件,用于展示列表數(shù)據(jù),本文主要介紹了Python QListView教程的實現(xiàn),具有一定的參考價值,感興趣的可以了解一下
    2025-04-04
  • python可視化分析的實現(xiàn)(matplotlib、seaborn、ggplot2)

    python可視化分析的實現(xiàn)(matplotlib、seaborn、ggplot2)

    這篇文章主要介紹了python可視化分析的實現(xiàn)(matplotlib、seaborn、ggplot2),文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2021-02-02
  • django連接mysql配置方法總結(jié)(推薦)

    django連接mysql配置方法總結(jié)(推薦)

    這篇文章主要介紹了django連接mysql配置方法總結(jié)(推薦),小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2018-08-08
  • 修改Python的pyxmpp2中的主循環(huán)使其提高性能

    修改Python的pyxmpp2中的主循環(huán)使其提高性能

    這篇文章主要介紹了修改Python的pyxmpp2中的主循環(huán)使其提高性能,pyxmpp2是Python中使用需XMPP協(xié)議的一個常用工具,要的朋友可以參考下
    2015-04-04
  • Python動態(tài)導入模塊的方法實例分析

    Python動態(tài)導入模塊的方法實例分析

    這篇文章主要介紹了Python動態(tài)導入模塊的方法,結(jié)合實例形式較為詳細的分析了Python動態(tài)導入系統(tǒng)模塊、自定義模塊以及模塊列表的相關(guān)操作技巧,需要的朋友可以參考下
    2018-06-06
  • 詳解python如何調(diào)用C/C++底層庫與互相傳值

    詳解python如何調(diào)用C/C++底層庫與互相傳值

    Python作為一門腳本解釋語言,本身又很好的結(jié)合C++,所以使用Python開發(fā),在性能要求的地方調(diào)用C/C++底層庫,這簡直是神器。本文詳細介紹了Python調(diào)用C/C++底層庫,互相傳值問題,下面一起來看看。
    2016-08-08
  • Django中ajax發(fā)送post請求 報403錯誤CSRF驗證失敗解決方案

    Django中ajax發(fā)送post請求 報403錯誤CSRF驗證失敗解決方案

    這篇文章主要介紹了Django中ajax發(fā)送post請求 報403錯誤CSRF驗證失敗解決方案,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2019-08-08
  • Python命令行參數(shù)解析模塊getopt使用實例

    Python命令行參數(shù)解析模塊getopt使用實例

    這篇文章主要介紹了Python命令行參數(shù)解析模塊getopt使用實例,本文講解了使用語法格式、短選項參數(shù)實例、長選項參數(shù)實例等內(nèi)容,需要的朋友可以參考下
    2015-04-04
  • Python獲取文件ssdeep值的方法

    Python獲取文件ssdeep值的方法

    這篇文章主要介紹了Python獲取文件ssdeep值的方法,是一個比較實用的技巧,本文詳細講述了實現(xiàn)這一功能的具體步驟及相關(guān)注意事項,需要的朋友可以參考下
    2014-10-10

最新評論