0

我正在寻找一种可以获取 sendmail 邮件列表(即可以成为:include:别名文件中指令目标的文本文件)并解析它们以生成收件人列表的工具。当然,这些文件可以包含评论、除实际地址外还有“描述性”名称的收件人、外部地址和本地用户以及其他别名的混合等。

是否存在进行此解析的工具,或允许我自己编写的正式规范?还是我必须编写一个几乎可以肯定包含错误的临时文件?

我没有对我正在处理的服务器的 root 访问权限,所以sendmail -bv不起作用。(当然,如果我只是需要将它用作独立于实际设置的实用程序,我总是可以设置自己的安装。)sendmail -bt似乎确实有效,但我不完全确定如何使用它。

4

1 回答 1

0

这是我最终用来解决这个问题的 Python 代码。您必须对其进行调整才能在与我的配置不同的服务器上工作。

import os
import re
import subprocess

def find_recipients(usernames):
    recipients = {'local': set(), 'external': set(), 'missing_local': set(),
                  'file': set(), 'program': set(), 'error_messages': set()}
    visited_lists = set()
    sendmail = subprocess.Popen(('sendmail', '-bt'), stdin=subprocess.PIPE,
                                stdout=subprocess.PIPE)
    def handle_local_user(username):
        username = username.lower()
        list_path = '/shared/aliases/' + username
        if os.path.isfile(list_path):
            visit_list(list_path)
        elif os.path.isdir('/home/' + username):
            recipients['local'].add(username)
        else:
            recipients['missing_local'].add(username)
    def visit_list(list_path):
        if list_path not in visited_lists:
            visited_lists.add(list_path)
            with open(list_path, 'r') as ml_file:
                for ml_line in ml_file:
                    if not re.match(r'^\s*(#.*)?$', ml_line):
                        if not ml_line.endswith('\n'):
                            ml_line += '\n'
                        sendmail.stdin.write('/parse ' + ml_line)
                        sendmail.stdin.flush()
                        match = None
                        while match is None:
                            match = re.match(r'^mailer ([^,]*), (.*)\n$',
                                             sendmail.stdout.readline())
                        mailer, recipient_info = match.groups()
                        if mailer == 'local':
                            handle_local_user(
                                re.match(r'^user (.+)$',
                                         recipient_info).group(1))
                        elif mailer == 'relay':
                            user, at, domain = re.match(
                                r'^host smtp\.mydomain\.org, user (.*)$',
                                recipient_info).group(1).partition('@')
                            domain = domain.lower()
                            if domain == 'mydomain.org':
                                handle_local_user(user)
                            else:
                                recipients['external'].add(user + at + domain)
                        elif mailer == '*file*':
                            recipients['file'].add(
                                re.match(r'^user (.+)$',
                                         recipient_info).group(1))
                        elif mailer == 'prog':
                            recipients['program'].add(
                                re.match(r'^user (.+)$',
                                         recipient_info).group(1))
                        elif mailer == '*include*':
                            visit_list(re.match(r'^user (.+)$',
                                                recipient_info).group(1))
                        elif mailer == '*error*':
                            raise RuntimeError('address parsing error: ' +
                                               recipient_info)
                        else:
                            raise RuntimeError('unrecognized mailer: ' +
                                               mailer)
    for un in usernames:
        handle_local_user(un)
    sendmail.communicate('/quit')
    return recipients
于 2013-02-06T01:56:15.630 回答