📜 ⬆️ ⬇️

How to deliver e-mail notifications to clients in the conditions of impossibility to register a reverse DNS zone

Proof of concept


From such a title it is quite difficult to understand, “but who needs it at all?”, And therefore, for a start, a brief preface.

It's no secret that Internet providers are very aggressive looking at small businesses. The terms of service for individuals and legal entities are about the same, but the price varies considerably. The situation of the monopoly has been corrected to some extent with the advent of standards such as LTE and 4G, but the conditions of service still remain very far from humanity. So, this article is dedicated to those who, for some reason or other, are forced to interact with a provider that provides an external IP address, but does not allow editing the corresponding reverse DNS records.

Surely, many people know that as a requirement for mail servers, in addition to DKIM records and other checks, there is also a mandatory reverse DNS record. Otherwise, the letters will either not reach at all, or they will fall into the “Spam” folder. With the above facts further we will understand.
')

main idea


What options remain? First, these are transparent SMTP proxying services. But in this case, the client will receive letters from a third-party domain, which, quite naturally, may cause the client’s distrust of your resource. Secondly, it is magic. In the direction of the latter, and we will think.

The idea is to get rid of your IP like an initial relay. This will help us with Gmail Hosted. The procedure for setting up your domain to use Gmail Hosted is quite simple and well documented. For all the details here: Google Apps for Business .

After setting up your domain to work with the services of Gmail Hosted and registering the corresponding mailbox to communicate with clients (suppose it is noreply@yourdomain.com), I really want to notify your customers about events from the code of your resource. But if in such a configuration try to use the account noreply@yourdomain.com as a relay, then we get the same thing that we’ve left. Hiring an employee who would log into the web interface and send alerts is unwise.

Lot of code


In my example, I use OS FreeBSD, so “as is” this example can only be used in it.

There is a great console browser elinks, which can do a lot of things, but not JavaScript. No matter how the documentation assures you of the opposite, this is not the case, elinks interprets JavaScript only as a language for scripting user actions. But, anyway, this should not stop us, because Gmail still maintains compatibility with browsers that lack JavaScript interpreter support.

How it will work:



At once I will make a reservation that the mechanisms used by me do not pretend to elegance, the task before me was to make the mandrel take place and not the process optimization under high load.

We will need:



If there is a need to describe the installation process of all necessary, write in the comments, but I take the liberty to assume that those who have attended to such a problem are already familiar with the process of installing and configuring applications.

Take the bull by the horns


Interception of mail () built-in php function, output of mail () function arguments to external execution environment

To any constantly included area of ​​the page of your project, we add the following code:

function my_mail($args) { $result = $args[0] . "\n"; $result .= $args[1] . "\n"; $result .= $args[2]; $file = '/tmp/msg.exchange'; $current = $result . "\n"; file_put_contents($file, $current); fclose($file); exec('/usr/local/bin/sudo /bin/csh /root/exec.sh > /dev/null &'); return 1; } override_function('mail', '', 'my_mail(func_get_args());'); 


Here, the mail () function arguments such as “To”, “Subject”, “Body” are saved to the file “/tmp/msg.exchange” stored in memory. Next, the main body of the script is called with the redirection of the stdout stream to the null device so that the page loads immediately, without waiting for the script to finish.

Immediately it is worth noting the assignment of rights in the file "/ usr / local / etc / sudoers":
 Defaults:www !requiretty www ALL=(ALL) NOPASSWD: /usr/local/bin/elinks, /usr/local/bin/python, /usr/bin/su, /bin/csh 


Attention! the string “Defaults: www! requiretty” is necessary, because if it does not exist, you will receive an error in the log of your web server stating that it is impossible to start the application in headless mode without selecting a separate tty device.

Running elinks, logging in to Gmail

For the elinks to work correctly with the Russian language, you will need a little tweaking:
 mkdir ~/.elinks printf 'set terminal.xterm.charset = "koi8-r"\nset ui.language = "Russian"\nset document.browse.search.regex = 0' >> ~/.elinks/elinks.conf 


As such, authorization at each launch we will not need. Elinks will cope with it. It’s enough to log in once on the page “elinks mail.google.com/mail/u/0 \? Ui = html \ & zy = c”, and then this data will be used in all subsequent sessions.

Further, since we already have a call to the sh script, I will give its code:

/root/exec.sh
 #!/bin/sh su -l setenv LANG ru_RU.KOI8-R /usr/local/bin/python /root/headless.py 

The indirect call of the python script is associated with some features of the work of mechanisms for changing rights and features of the work of encodings in headless mode.

Go to the letter creation page, fill in the appropriate letter fields, send the form and then send the letter

The last items are combined, because the logic of the script does not allow to distinguish them in this way. For a better understanding of the mechanism, I will have to first provide the code associated with filling out the submission form, and only then bring the browser call script and its management.

Filling in the appropriate letter fields

Scripting user-defined functions is a very convenient mechanism in elinks. It allows you to perform certain macros in response to the occurrence of certain events. In particular, the pre_format_html_hook event occurs when the browser has already loaded the contents of the page, but before interpreting it from the HTML view to the form in which we will see it. But, as stated in the Lua documentation for the elinks scripting part, not all Lua mechanisms work correctly within the framework of the Lua <-> elinks interaction. For example, when attempting to call Lua's built-in file reading functions, both executable files behave in an unpredictable way, so you have to bypass this restriction by using the specially written function pipe_read, which is essentially a simple receiver of the stdout stream from executing any binary elf code . It is also worth noting a moment with encodings: in fact, nothing complicated, but working with the received HTML lines is in the encoding in which they came, because the search strings will look completely unreadable.

All user scripts are located in the ~ / .elinks folder and are named hooks.lang, where lang is the name of the scripting language. In my case, this is ~ / .elinks / hooks.lua, the contents of which are listed below:
/root/.elinks/hooks.lua
 function pre_format_html_hook (url, html) toaddress = pipe_read("head -n 1 /tmp/msg.exchange") nstr = pipe_read("cat /tmp/msg.exchange | tail -n+2 | /usr/local/bin/iconv -f windows-1251 -t koi8-r | /usr/local/bin/iconv -f koi8-r -t utf-8") theme = pipe_read("head -n 2 /tmp/msg.exchange | tail -n+2 | /usr/local/bin/iconv -f windows-1251 -t koi8-r | /usr/local/bin/iconv -f koi8-r -t utf-8") html1 = string.gsub (html, 'aria%-labelledby=l%-to>', 'aria%-labelledby=l%-to>' .. toaddress) html1 = string.gsub (html1, 'input name=subject value=""', 'input name=subject value="' .. theme .. '"') html1 = string.gsub (html1, 'aria%-label="╒╣╩╬ ©╦│▄╪╟">', 'aria%-label="╒╣╩╬ ©╦│▄╪╟">' .. nstr) return html1 end 


Total, on each page containing the necessary field names, there will be an autocomplete such. You can easily verify this by running elinks, and going to the send mail page.

Go to the letter creation page, send the form and then send the letter

This stage was perhaps the most difficult. Having tried all the tools in trying to send special characters to the already spawned process, such as Enter and pressing the right key, I came across a wonderful python library called pyexpect. With her everything instantly became very simple and clear. Just give the code:
/root/headless.py
 #!/usr/bin/python # -*- coding: koi8-r -*- from pexpect import spawn import time import datetime import base64 import pickle ''' fd = open('/tmp/msg.exchange', 'r+') with fd as f: lines = f.read().splitlines() theme = lines[1] theme = theme.replace("=?windows-1251?B?", "") theme = theme.replace("?=", "") lines[1] = base64.b64decode(theme) fd = open('/tmp/msg.exchange', 'r+') fd.truncate() for item in lines: fd.write("%s\n" % item) fd.close() ''' #KEY_UP = '\x1b[A' #KEY_DOWN = '\x1b[B' #KEY_RIGHT = '\x1b[C' #KEY_LEFT = '\x1b[D' #KEY_ESCAPE = '\x1b' #KEY_BACKSPACE = '\x7f' child = spawn('/usr/local/bin/elinks https://mail.google.com/mail/u/0/?ui=html&zy=c') #child.logfile = open('/tmp/elinks.log', 'r+') print 'waiting for gmail.com to load' child.expect('ORGNAME') time.sleep(0.5) child.sendline('/') print 'search of "new message" string has been reached' child.sendline('') print 'the enter key after searching "new message" button has been emulated' child.expect('') print 'weve got "send" string back from server' child.sendline('/') print 'search of "send" string has been reached' child.sendline('') print 'emulated enter key for submitting completed form' child.sendline('') print 'emulated enter key for accepting dialog' child.expect('') print 'got signal about sucssefull message sending' #child.interact() time.sleep(2) child.sendline('q') print 'sent quit key emulation' child.sendline('') print 'accepted quit with enter key' 


Here I deliberately left a lot of interesting commented lines. A multi-line comment is a code specific to the Bitrix engine. The fact is that the bitrix with its system of mail templates automatically encodes a string with the subject of the letter in base64 encoding. In this piece of code, decoding from base64 to plain text occurs, followed by writing back to the exchange file. KEY_UP, KEY_DOWN, etc. are special character codes for the corresponding keys, up, down, etc. The string "child.logfile = open ('/ tmp / elinks.log', 'r +')" is very, very useful for debugging a script in headless mode. The string “child.interact ()” is useful when debugging a script in the normal execution mode from the console.

To use this “as is” script, replace ORGNAME with the name of your organization as it appears in the Gmail header.

Regarding the limitations of this method, yes, they are not small. First is the speed. It takes a considerable amount of time and computing resources to send each letter. No way to send beautifully formatted HTML emails. Scripts need some work to send applications.

But there are a lot of advantages, for example, this method can be used even if you have a dynamic IP address that works, say, in conjunction with No-IP. But perhaps the main advantage of this method is a complete imitation of manual input to the Gmail web interface, and as a result, spam filtering will work exclusively with the text of the letter, and those with the formal signs of the sender. In my case, the letters sent by this method come not just to the inbox, but to the inbox marked as important.

Thank you for your attention, comrades Habrovca, successful deliveries to you.

Source: https://habr.com/ru/post/232261/


All Articles