Python 用于为收件箱子目录中的电子邮件自动创建dovecot.sieve规则的脚本

Python 用于为收件箱子目录中的电子邮件自动创建dovecot.sieve规则的脚本,python,bash,email,dovecot,sieve-language,Python,Bash,Email,Dovecot,Sieve Language,在浏览/使用这个伟大网站上的解决方案一段时间后,我终于可以参与了 我对我想要的东西有一个非常清楚的概念,但我正在寻找最好的方法去实现 我想要什么?: 有一段时间,我在raspberry pi上使用电子邮件服务器设置,到目前为止效果很好。 它由一个dovecot服务器和一些筛选过滤器组成,设置这些过滤器可以将我的许多电子邮件地址排序到单独的收件箱子目录中。 还有一个垃圾邮件过滤器,每天晚上都会通过脚本教给他火腿和垃圾邮件的区别。 (基本上,他被告知垃圾邮件在垃圾邮件文件夹中,其他文件夹都包含火腿)

在浏览/使用这个伟大网站上的解决方案一段时间后,我终于可以参与了

我对我想要的东西有一个非常清楚的概念,但我正在寻找最好的方法去实现

我想要什么?:

有一段时间,我在raspberry pi上使用电子邮件服务器设置,到目前为止效果很好。 它由一个dovecot服务器和一些筛选过滤器组成,设置这些过滤器可以将我的许多电子邮件地址排序到单独的收件箱子目录中。 还有一个垃圾邮件过滤器,每天晚上都会通过脚本教给他火腿和垃圾邮件的区别。 (基本上,他被告知垃圾邮件在垃圾邮件文件夹中,其他文件夹都包含火腿)

我想将这种行为复制到一个专用的“时事通讯”文件夹中。 此文件夹不包含需要立即查看或报告的紧急邮件

计划是手动将电子邮件放入“新闻”文件夹,并让脚本每天扫描该文件夹一次。如果它发现一封来自没有筛选规则的地址的电子邮件,它应该创建一个规则,在到达时自动将来自该地址的邮件放入“新闻”文件夹

实现步骤?:

  • 为此,脚本需要扫描现有的.dovecot.sieve文件, 将“新闻文件夹”规则中的地址提取到单独的文件中 或用于比较的对象

    /*Example of a sieve filter:*/
    
    require "fileinto";
    
     /* Global Spam Filter */
    if anyof (header :contains "subject" "*SPAM*",
              header :contains "X-Spam-Flag" "YES" ) {
      fileinto "Junk";
      stop;
    }
    
    /* LAN Emails Filter */
      elsif address :is "to" "lan@docbrown.pi" {
      fileinto "INBOX.Lokal";
      stop;
    }
    
    /* Newsletter Filter */
      elsif anyof (address :is "from" "newsletter@example.com",
                   address :is "from" "news@yahoo.de",
                   address :is "from" "info@mailbox.de",
                   address :is "from" "something@somewhere.de") {
      fileinto "INBOX.Newsletter";
      stop;
    }
    
     /* gmail Account Filter */
      elsif address :is "to" "docbrown@gmail.com" {
      fileinto "INBOX.gmail";
      stop;
    }
    
     /* Yahoo Account Filter */
      elsif address :is "to" "docbrown@yahoo.de" {
      fileinto "INBOX.yahoo";
      stop;
    }
    
      else {
      # The rest goes into INBOX
      # default is "implicit keep", we do it explicitly here
      keep;
    }
    
  • 然后它将需要处理所有的电子邮件 “新闻”文件夹的maildir目录,并在电子邮件中搜索 对于“发件人:”字段和尖括号中的电子邮件地址

    Date: Mon, 4 Nov 2013 16:38:30 +0100 (CET)
    From: Johannes Ebert - Redaktion c't <infoservice@heise.de> 
    To: docbrown@example.de
    
    因此,我想知道是否可以通过使用python更轻松地实现这一点。 我在另一个raspberry项目中修补了它,但没有时间完全沉浸在python世界中

    因此,我很乐意在这里得到一些帮助/建议/指出正确的方向

    到目前为止,我为一个类似的问题(第一部分)找到了一些解决方案,其中需要提取,但我无法完全适应它,或者由于无法执行脚本而犯了一些错误

    #!/usr/bin/python
    
    file = open("dovecot.sieve", "r")
    
    rule = {}
    current_rule = None
    
    for line in file:
        line = line.split()
    
        if (line[2] == "INBOX.Newsletter"):
            break
        if (line[1] == "/* Newsletter Filter */"):
            current_rule = rule.setdefault('Newsletter', [])
            continue
        if (line[5] == "from"):
            current_rule.append(line[6])
            continue
        if (line[3] == "from"):
            current_rule.append(line[4])
            continue
    
    
    file.close()
    
    # Now print out all the data
    import pprint
    print "whole array"
    print "=============================="
    pprint.pprint(rule)
    print 
    print "addresses found"
    print "=========================="
    pprint.pprint(rule['Newsletter'])
    

    有人能推荐一个python的IDE,它带有调试器等等吗?Eclipse会出现在我的脑海中,或者还有其他什么(可能不是那么需要资源)?

    好的,所以我有一些空闲时间来解决我自己的问题。做了一些深入研究,阅读了一些代码片段,并在Eclipse中使用Pydev对其进行了测试

    现在,我在夜间将此脚本作为cron作业运行

    它有什么作用?

    它收集dovecot.sieve文件中的所有电子邮件地址(以及“新闻稿”规则集中的电子邮件地址)。然后在INBOX.Newsletter文件夹中查找任何未注册的电子邮件地址,方法是将其与收集的地址进行比较。 如果它找到一个新地址,它会保存一个旧的sieve文件的副本,然后重写现有的文件。新的电子邮件地址将插入“新闻稿”规则集中,以便将这些电子邮件重定向到指定的新闻稿文件夹中

    #!/usr/bin/python2.7
    
    import os, sys
    #Get the already configured email senders...
    addresses = {}
    current_addresses = None
    
    with open("/home/postman/.dovecot.sieve", "r") as sieveconf:
        for line in sieveconf:
            if "INBOX.Newsletter" in line:
                break
    
            if "Newsletter Filter" in line:
                current_addresses = addresses.setdefault('found', [])
                continue
    
            if "from" in line and current_addresses != None:
                line = line.split('"')
    
                if (len(line) > 4) and (line[1] == "from"):
                    current_addresses.append(line[3])
    
                    continue
    
    #save the count for later
    addr_num = 0
    addr_num = len(addresses['found'])
    
    #iterate all files in all sub-directories of INBOX.Newsletter
    for root, _,files in os.walk("/home/postman/Mails/.INBOX.Newsletter"):
        #for each file in the current directory
        for emaildir in files:
            #open the file
            with open(os.path.join(root, emaildir), "r") as mail:
                #scan line by line
                for line in mail:
                    if "From: " in line:
                        #arm boolean value for adding to list
                        found_sw = False
                        #extract substring from line
                        found = ((line.split('<'))[1].split('>')[0])
                        #compare found address with already existing addresses in dictionary
                        for m_addr in addresses['found']:
                            if m_addr == found:
                                #remember if the address is already in the dictionary
                                found_sw = True
                                break
    
                        if not found_sw:
                            #if the address is not included in the dictionary put it there
                            current_addresses.append(found)
                        break
    
    
    # Now print out all the data
    #import pprint
    #print "addresses found:"
    #print "=========================="
    #pprint.pprint(addresses['found'])
    #print
    #print "orig_nmbr_of_addresses:" , addr_num
    #print "found_nmbr_of_addresses:", len(addresses['found'])
    #print "not_recorded_addresses:", (len(addresses['found']) - (addr_num))
    
    #Compare if the address count has changed
    if addr_num == len(addresses['found']):
        #exit the script since no new addresses have been found
        sys.exit
    else:
        #copy original sieve file for backup
        import datetime
        from shutil import copyfile
        backupfilename = '.backup_%s.sieve'% datetime.date.today()
        copyfile('dovecot.sieve', backupfilename)
    
        #edit the existing sieve file and add the new entries
        import fileinput
        #open file for in place editing
        for line in fileinput.input('dovecot.sieve', inplace=1):
            #if the line before the last entry is reached
            if addresses['found'][(addr_num - 2)] in line:
                #print the line
                print line,
                #put new rules before the last line (just to avoid extra handling for last line, since the lines before are rather identical)
                for x in range (addr_num, (len(addresses['found']))):
                    print '               address :is "from" "%s",'% addresses['found'][x]
            else:
                #print all other lines
                print line,
    
    #/usr/bin/python2.7
    导入操作系统,系统
    #获取已配置的电子邮件发件人。。。
    地址={}
    当前地址=无
    以open(“/home/postman/.dovecot.sieve”,“r”)作为sieveconf:
    对于SiveConf中的行:
    如果行中有“收件箱.新闻稿”:
    打破
    如果行中有“新闻稿过滤器”:
    当前地址=地址.setdefault('found',[])
    持续
    如果行中的“发件人”和当前地址!=无:
    line=line.split(“”)
    如果(len(line)>4)和(line[1]=“from”):
    当前_地址。追加(第[3]行)
    持续
    #保存计数以备以后使用
    addr_num=0
    addr_num=len(地址['found'])
    #迭代INBOX.Newsletter所有子目录中的所有文件
    对于root用户,x,os.walk(“/home/postman/mail/.INBOX.Newsletter”)中的文件:
    #对于当前目录中的每个文件
    对于文件中的emaildir:
    #打开文件
    打开(os.path.join(root,emaildir),“r”)作为邮件:
    #逐行扫描
    对于邮寄线路:
    如果“发件人:”在同一行:
    #用于添加到列表的arm布尔值
    发现\u sw=False
    #从行中提取子字符串
    找到=((行分割(“”)[0])
    #将找到的地址与字典中已有的地址进行比较
    对于m_addr in地址['found']:
    如果m_addr==找到:
    #记住地址是否已经在字典中
    已找到\u sw=True
    打破
    如果未找到\u sw:
    #如果字典里没有地址,就把它放在那里
    当前_地址。追加(已找到)
    打破
    #现在打印出所有数据
    #导入pprint
    #打印“找到的地址:”
    #打印“========================================”
    #pprint.pprint(地址['found'])
    #印刷品
    #打印“原始地址:”,地址编号
    #打印“找到的地址:”,len(地址['found'])
    #打印“未记录的地址:”,(len(地址['found'])-(addr_num))
    #比较地址计数是否已更改
    如果addr_num==len(地址['found']):
    #由于未找到新地址,请退出脚本
    系统出口
    其他:
    #复制原始筛选文件以进行备份
    导入日期时间
    从shutil导入复制文件
    backupfilename='.backup_u%s.siever'%datetime.date.today()
    复制文件('dovecot.sieve',备份文件名)
    #编辑现有的筛选文件并添加新条目
    导入文件输入
    #打开文件进行就地编辑
    对于fileinput.input('dovecot.sieve',inplace=1)中的行:
    #如果到达最后一个条目之前的行
    如果第行中的地址['found'][(addr_num-2)]:
    #打印行
    打印行,
    #将新规则放在最后一行之前(只是为了避免对最后一行进行额外处理)
    
    #!/usr/bin/python2.7
    
    import os, sys
    #Get the already configured email senders...
    addresses = {}
    current_addresses = None
    
    with open("/home/postman/.dovecot.sieve", "r") as sieveconf:
        for line in sieveconf:
            if "INBOX.Newsletter" in line:
                break
    
            if "Newsletter Filter" in line:
                current_addresses = addresses.setdefault('found', [])
                continue
    
            if "from" in line and current_addresses != None:
                line = line.split('"')
    
                if (len(line) > 4) and (line[1] == "from"):
                    current_addresses.append(line[3])
    
                    continue
    
    #save the count for later
    addr_num = 0
    addr_num = len(addresses['found'])
    
    #iterate all files in all sub-directories of INBOX.Newsletter
    for root, _,files in os.walk("/home/postman/Mails/.INBOX.Newsletter"):
        #for each file in the current directory
        for emaildir in files:
            #open the file
            with open(os.path.join(root, emaildir), "r") as mail:
                #scan line by line
                for line in mail:
                    if "From: " in line:
                        #arm boolean value for adding to list
                        found_sw = False
                        #extract substring from line
                        found = ((line.split('<'))[1].split('>')[0])
                        #compare found address with already existing addresses in dictionary
                        for m_addr in addresses['found']:
                            if m_addr == found:
                                #remember if the address is already in the dictionary
                                found_sw = True
                                break
    
                        if not found_sw:
                            #if the address is not included in the dictionary put it there
                            current_addresses.append(found)
                        break
    
    
    # Now print out all the data
    #import pprint
    #print "addresses found:"
    #print "=========================="
    #pprint.pprint(addresses['found'])
    #print
    #print "orig_nmbr_of_addresses:" , addr_num
    #print "found_nmbr_of_addresses:", len(addresses['found'])
    #print "not_recorded_addresses:", (len(addresses['found']) - (addr_num))
    
    #Compare if the address count has changed
    if addr_num == len(addresses['found']):
        #exit the script since no new addresses have been found
        sys.exit
    else:
        #copy original sieve file for backup
        import datetime
        from shutil import copyfile
        backupfilename = '.backup_%s.sieve'% datetime.date.today()
        copyfile('dovecot.sieve', backupfilename)
    
        #edit the existing sieve file and add the new entries
        import fileinput
        #open file for in place editing
        for line in fileinput.input('dovecot.sieve', inplace=1):
            #if the line before the last entry is reached
            if addresses['found'][(addr_num - 2)] in line:
                #print the line
                print line,
                #put new rules before the last line (just to avoid extra handling for last line, since the lines before are rather identical)
                for x in range (addr_num, (len(addresses['found']))):
                    print '               address :is "from" "%s",'% addresses['found'][x]
            else:
                #print all other lines
                print line,