Re: [exim] Warm IP by limiting outgoing SMTP by destination

Top Page
Delete this message
Reply to this message
Author: Rory Campbell-Lange
Date:  
To: Jeremy Harris
CC: exim-users
Subject: Re: [exim] Warm IP by limiting outgoing SMTP by destination
On 07/03/19, Jeremy Harris via Exim-users (exim-users@???) wrote:
> There's a page on the wiki with some ideas on rate limiting outbound. It is unfortunately much harder than rate limiting inbound in Exim.


Thanks Jeremy

I glanced at the page. https://github.com/Exim/exim/wiki/RatelimitOutbound
mentions "redirect supplied by an acl expansion" or "msg:delivery Event"
or a queue-runner methodology.

While the first looks quite interesting I've made my sketch in the
previous email work. It is an external programme linked to a very simple
sqlite database recording day | domain | counter. It seems to work, as a
first router on a stock Debian setup.

    dns_warmup:
      debug_print = "R: dns_warmup for $local_part@$domain"
      driver = dnslookup
      domains = aol.com : yahoo.com # ... etc ...
      transport = remote_smtp
      same_domain_copy_routing = no
      condition = ${run{/fullpath/exim_domain_warmup.py "$domain"}{yes}{no}}
      no_more


I'm using the script below in case anyone finds it useful.

Thanks
Rory


-- begin script --

#!/usr/bin/python

""" exim_domain_warmup.py """

import sqlite3
import sys
from datetime import datetime

# settings
dbname = 'domain_count.db'
STARTDATE = '2019-03-07'  # start date for sending
STARTEMAILS = 4           # number of start emails to send per domain


# calculate dates
datefmt = ("%Y-%m-%d")
datestart = datetime.strptime(STARTDATE, datefmt)
today = datetime.today()
todaystr = today.strftime(datefmt)
datedelta = today - datestart

DAYDELTA = datedelta.days + 1

def day_mail_limit(startemails=STARTEMAILS, days=DAYDELTA):
    """
    Work out how many emails to send based on the start amount of emails
    and days elapsed since the start date
    """
    if days < 1:
        return False
    # 25 : 50 : 100 etc
    return startemails * (2 ** (days-1))



def dbinit():
    """database table init"""
    conn = sqlite3.connect(dbname, timeout=3)
    conn.execute(r'''
        CREATE TABLE IF NOT EXISTS domaincounter (
            dater TEXT, domain TEXT, counter INT
        )
    ''')
    conn.commit()



def domain_check(domain):
    """
    Check if the domain is in the db, against today
    """


    # work out current day limits
    domainlimit = day_mail_limit()
    if not domainlimit:
        return False


    conn = sqlite3.connect(dbname, timeout=3)


    q = conn.execute(r'''SELECT * FROM domaincounter WHERE dater=? AND domain=?''',
        (todaystr, domain))
    r = q.fetchone()


    if not r:
        conn.execute(r'''INSERT INTO domaincounter VALUES (?, ?, ?)''',
            (todaystr, domain, 1)
        )
        conn.commit()
        return True


    else:
        # if over limit return
        if r[2] >= domainlimit:
            conn.commit()
            return False


        # update record
        conn.execute(r'''
                UPDATE domaincounter SET dater=?, domain=?, counter=?
                WHERE dater=? AND domain=?''',
            (todaystr, domain, r[2] + 1, todaystr, domain))
        conn.commit()
        return True



if __name__ == '__main__': 
    # read sys.argv1 (domain name from exim)
    try:
        domain = sys.argv[1]
    except:
        sys.exit(1)


    # dbinit()


    dc = domain_check(domain)
    if not dc:
        sys.exit(1)
    else:
        sys.exit(0)