0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

Postfixでgmail宛の制限

Last updated at Posted at 2023-12-12

Postfixでgmail宛の制限

gmail宛に1秒間隔、同時接続数3を実現したい。
smtp-destination_concurrency_limit
smtp-destination_rate_delay
は同時に設定できない(同時に設定しても同時接続数1になる)ので、
無理矢理実現。

以下は頑張って読もう
https://www.postfix-jp.info/trans-2.1/jhtml/access.5.html

mkdir -p /etc/postfix/userprogram/bin/
mkdir -p /etc/postfix/userprogram/def/
mkdir -p /etc/postfix/userprogram/log/
chown -R nobody:nobody /etc/postfix/userprogram/
/etc/postfix/userprogram/bin/check_policy_service.py
import sys
import logging
import socket
import os
import re
import yaml
from pathlib import Path
import random

# テスト用
import io
if len(sys.argv) > 1:
    sys.stdin = io.StringIO(sys.argv[1])

#===============================================================================
# ロギング設定
#===============================================================================
def setup_logging():
    host_name = socket.gethostname()
    program_name = os.path.basename(__file__)
    log_name = Path(__file__).stem + '.log'
    log_file_path = Path(__file__).resolve().parent.parent / 'log' / log_name
    logger = logging.getLogger()
    logger.setLevel(logging.INFO)
    file_handler = logging.FileHandler(log_file_path, encoding='utf-8')
    file_handler.setFormatter(logging.Formatter(f'%(asctime)s {host_name} [{program_name}:%(levelname)s] [%(process)d] %(message)s', datefmt='%Y-%m-%d %H:%M:%S'))
    stream_handler = logging.StreamHandler(sys.stdout)
    stream_handler.setFormatter(logging.Formatter(f'%(asctime)s {host_name} [{program_name}:%(levelname)s] [%(process)d] %(message)s', datefmt='%Y-%m-%d %H:%M:%S'))
    logger.addHandler(file_handler)
    logger.addHandler(stream_handler)

#===============================================================================
# ユーティリティ関数
#===============================================================================
def load_transport_config(config_path):
    """
    設定ファイルの読み込み。YAML構造が変更されたため、適応。
    """
    with open(config_path, 'r') as file:
        config = yaml.safe_load(file)  # YAMLファイルの読み込み
    services_config = config['check_policy_services']  # 新しいトップレベルキーに対応
    compiled_services = []
    for service_item in services_config:
        for service_name, settings in service_item.items():
            compiled_domains = [re.compile(domain) for domain in settings['domains']]
            compiled_services.append({
                'name': service_name,
                'domains': compiled_domains,
                'range': settings['range']
            })
    return compiled_services

def match_domain(transport_config, recipient_domain):
    """
    ドメインの一致を判定する。
    """
    for service in transport_config:
        for domain_pattern in service['domains']:
            if domain_pattern.match(recipient_domain):
                return service['name'], service['range']
    return None, None

#================================================================================
# メイン関数
#================================================================================
def main():
    # ロギング設定の初期化
    setup_logging()

    # 設定ファイルのパス
    config_path = Path(__file__).resolve().parent.parent / 'def' / (Path(__file__).stem + '.yaml')
    transport_config = load_transport_config(config_path)

    try:
        for line in sys.stdin:
            line = line.strip()
            if line == "":
                logging.info("Empty line detected, stopping.")
                break
            if line.startswith("recipient="):
                recipient = line.split("recipient=")[-1]
                if "@" not in recipient:
                    print("action=DUNNO\n")
                    logging.error(f"{recipient}: action=DUNNO, Invalid email address")
                    continue
                recipient_domain = '@' + recipient.split("@")[-1]
                service, rng = match_domain(transport_config, recipient_domain)
                if service:
                    selected_number = random.randint(1, rng)
                    print(f"action=FILTER {service}{selected_number}:\n")
                    logging.info(f"{recipient}: action=FILTER {service}{selected_number}:")
                else:
                    print("action=DUNNO\n")
                    logging.info(f"{recipient}: action=DUNNO")
                sys.stdout.flush()
                break

    except Exception as e:
        logging.error(f"Error processing request: {e}")
        sys.exit(1)

if __name__ == "__main__":
    main()
/etc/postfix/userprogram/def/check_policy_service.yaml
check_policy_services:
  - docomo-smtp:
      domains:
        - '@docomo\.ne\.jp$'
        - '@disneymobile\.ne\.jp$'
      range: 4
  - au-smtp:
      domains:
        - '@ezweb\.ne\.jp$'
        - '@.+\.ezweb\.ne\.jp$'
      range: 3
  - softbank-smtp:
      domains:
        - '@softbank\.ne\.jp$'
        - '@[dhtckrnsq]\.vodafone\.ne\.jp$'
      range: 3
  - gmail-smtp:
      domains:
        - "@gmail.com$"
      range: 3
/etc/postfix/master.cf
policy_service unix - n n - - spawn
    user=nobody argv=/etc/postfix/userprogram/bin/check_policy_service.py
docomo-smtp1 unix - - - - - smtp
docomo-smtp2 unix - - - - - smtp
docomo-smtp3 unix - - - - - smtp
docomo-smtp4 unix - - - - - smtp
au-smtp1 unix - - - - - smtp
au-smtp2 unix - - - - - smtp
au-smtp3 unix - - - - - smtp
softbank-smtp1 unix - - - - - smtp
softbank-smtp2 unix - - - - - smtp
softbank-smtp3 unix - - - - - smtp
gmail-smtp1 unix - - - - - smtp
gmail-smtp2 unix - - - - - smtp
gmail-smtp3 unix - - - - - smtp
/etc/postfix/main.cf
smtpd_recipient_restrictions = check_policy_service unix:private/policy_service
docomo-smtp1_destination_rate_delay=1s
docomo-smtp2_destination_rate_delay=1s
docomo-smtp3_destination_rate_delay=1s
docomo-smtp4_destination_rate_delay=1s
au-smtp1_destination_rate_delay=1s
au-smtp2_destination_rate_delay=1s
au-smtp3_destination_rate_delay=1s
softbank-smtp1_destination_rate_delay=1s
softbank-smtp2_destination_rate_delay=1s
softbank-smtp3_destination_rate_delay=1s
gmail-smtp1_destination_rate_delay=1s
gmail-smtp2_destination_rate_delay=1s
gmail-smtp3_destination_rate_delay=1s
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?