В виндовой версии программы HFPager есть режим управления через электронную почту. Он позволяет отправлять эфирные сообщения на электронную почту и наоборот. Режим этот называется «Персональный e-mail шлюз» и полноценно работать умеет только с одним адресатом. К тому же требует соблюдения особых условий при формировании письма. Цитата из документации: «Кроме того, поле «Subject:» принятого письма должно включать в себя текст вида hfpager idFrom > idTo».
Чтобы сделать число почтовых юзеров больше чем один, а также для упрощения поля Subject, разработан промежуточный коннектор. Он с одной стороны получает письма от HFPager и пересылает их по списку юзеров. С другой стороны, письма юзеров пересылает на адрес пейджера. При этом в поле Subject можно просто написать id адресата. Или оставить его пустым, но в самом сообщении указать id в самом начале после символа правой скобки: вот такого >.
В каждое письмо, адресованное в сторону HFPager, скрипт добавляет позывной юзера, который прописан в файле maillist.txt. Письма с незнакомых адресов игнорятся.

Коннектор выполнен в виде скрипта на языке php. Запускается Планировщиком заданий прямо на компьютере с HFPager. Но можно вынести вообще на любой комп, имеющий доступ к используемым почтовым серверам.
Проверена работа с почтовыми клиентами K9 и Delta-Chat. С другими клиентами, возможно, придется допиливать обработку различных кодировок. Удачи вам в этом нелегком деле, не забудьте поделиться своими успехами.
Дополнительные материалы:
https://github.com/RA0UEK/HFP-Email-Connector — Материалы проекта на GitHub;
https://teletype.in/@shpagin/phpmailer — Вменяемая инструкция к PHPMailer. Отправка писем и файлов на почту.
UPD 17.07.2026 — Для локальных узлов КВП создан скрипт хранения и выдачи отложенных сообщений.
Скрипт в папке входящих сообщений от КВП ищет сообщения с тремя признаками:
— сообщение адресовано нашему КВП (на наш ID);
— сообщение принято правильно (в имени файла будет фигурировать такой фрагмент – «REC-OK»);
— сообщение содержит текст установленной формы, в нашем случае это стандартный радиолюбительский вопрос QRU?
Если все эти условия выполняются, то в ответ на запрос эфирного абонента формируется ответ. Если для эфирного абонента есть отложенные сообщения, то они по порядку кладутся в специальном виде в папку для отправки через КВП. Если сообщений нет, то формируется сообщение об отсутствии отложенных сообщений.
Отложенные сообщения хранятся в папке C:\USERNAME\<id адресата сообщений>
Сообщения представляют собой простые текстовые файлы с произвольным названием. Например. 1.txt, 2.txt, 3.txt и так далее. В файлах пишите все в одну строку без переносов каретки, скрипт не умеет читать более одной строки.
Скрипт написан на языке PHP и запускается Планировщиком заданий через пакетный файл .bat. В планировщике нужно указать период выполнения скрипта, например, «раз в минуту».
В программе КВП настроим взаимодействие с внешними программами.

Разложим проект где удобно на диске.

Положим в папку с ID эфирного абонента (которому предназначаются сообщения) текстовые файлы.
Не забудьте в скрипте PHP поправить ID вашего КВП. В моем случае это 2104, замените его на свой. В тексте программы есть комментарии в местах, где нужно его поменять.
Далее в Планировщике заданий создаем простое задание с запуском файла .bat раз в минуту.
Проверяем. Из эфира на номер вашего КВП направляем сообщение с текстом qru? Если все принято и настроено правильно, в ответ прилетит сначала сообщение о числе отложенных сообщений, а затем сами сообщения.
Код прилагается:
<?php
header('Content-Type: text/html; charset=utf-8');
$msgreceived = 'C:\LEV\RECEIVED'; // HFPager API config
$msgtosend = 'C:\LEV\SEND'; // HFPager API config
$dirqru = 'C:\LEV\QRU'; // Тут хранятся папки с отложенными сообщениями
echo "\n\n";
$msgarray = array_diff(scandir($msgreceived), ['.', '..']);
$count = array_key_last($msgarray);
foreach ($msgarray as $row) {
$row = $msgarray[$count];
$count = $count - 1;
If (strlen($row)>10) {
$stop_f = strpos($row,'.');
$start_f = 21;
// Error message files > dev/null
If (strpos($msgreceived.'/'.$row,'REC-ER')) {
echo "Error -- \033[31m[Ignore]\033[0m \n";
unlink($msgreceived.'/'.$row);
}
// Beacons files > dev/null
If (strpos($msgreceived.'/'.$row,'BEA')) {
echo "Beacon -- \033[31m[Ignore]\033[0m \n";
unlink($msgreceived.'/'.$row);
}
// GPS files > dev/null
If (strpos($msgreceived.'/'.$row,'GPS')) {
echo "GPS -- \033[31m[Ignore]\033[0m \n";
unlink($msgreceived.'/'.$row);
}
// Bad headers files > dev/null
If (strpos($msgreceived.'/'.$row,'REC-BD')) {
echo "Bad title -- \033[31m[Ignore]\033[0m \n";
unlink($msgreceived.'/'.$row);
}
// SNT-R-containing files
If (strpos($msgreceived.'/'.$row,'SNT-R')) {
echo "Sent message -- \033[31m[Ignore]\033[0m \n";
unlink($msgreceived.'/'.$row);
}
// REC-containing files
If (strpos($msgreceived.'/'.$row,'REC-OK')) {
echo "\033[32mMessage received correct\033[0m -- ";
$fd = fopen($msgreceived.'/'.$row, 'r') or die("ERR_OPEN_FILE");
$header='';
$message='';
$header = trim(fgets($fd,4096));
$header = str_replace("\r\n","",$header);
while(!feof($fd))
{
$sw = fgets($fd,4096);
$sw = str_replace("\n",'',$sw);
$sw = str_replace("\r",'',$sw);
If (($message!='') AND ($sw!='')) {
$message = $message.' '.$sw;
}
If (($message=='') AND ($sw!='')) {
$message = $sw;
}
}
fclose($fd);
$message = str_replace("\r\n","",$message);
// Message not for our ID
If (strpos($header,'> 2104') === false) { // Укажите тут ID своего КВП
echo "Not for us -- \033[31m[Ignore]\033[0m\n";
unlink($msgreceived.'/'.$row);
}
// If message for our ID
If (strpos($header,'> 2104')) { // Укажите здесь ID своего КВП
$serial = 0;
$er = substr($header,strpos($header,'Error Rate')+11);
$er = str_replace(' :','',$er);
$qru_id = trim(substr($header,0,strpos($header,' ')));
$header = substr($header,0,strpos($header,' '));
$text_for_terminal = iconv("Windows-1251", "UTF-8", $message);
$text_for_terminal = $header . ' ('. $er . ') > ' . $text_for_terminal;
echo "\033[32m" . $text_for_terminal . "\033[0m \n";
unlink($msgreceived.'/'.$row);
// START If message conteins 'QRU?'
If (stripos($message,'QRU?') !== false) {
echo "\033[32mRequest <QRU?>\033[0m -- \033[32m[SEND ANSVER]\033[0m";
$dirqru = $dirqru . '\\\\' . $qru_id;
If (file_exists($dirqru)) { // Если директория существует
$qru_count = 0;
$qru_array = array_diff(scandir($dirqru), array('.', '..'));
$qru_count = array_key_last($qru_array);
If ($qru_count > 0) { // Если в директории что-то есть
$qru_text = iconv("UTF-8","Windows-1251",'Msg: ' . $qru_count - 1 . '.');
$uta = date('YmdHis');
$filehfp = $msgtosend.'/1.dat';
$filehfpnew = $msgtosend.'/1.msg';
$hfptext = 'to=' . $qru_id . ',speed=0,askreq=1,resend=3' . "\n" . $qru_text . "\n";
file_put_contents($filehfp, $hfptext);
rename($filehfp, $filehfpnew);
sleep(10);
$smsarray = array_diff(scandir($dirqru), array('.', '..'));
$smscount = array_key_last($smsarray);
foreach ($smsarray as $srow) {
$srow = $smsarray[$smscount];
$smscount = $smscount - 1;
$smsfile = fopen($dirqru.'/'.$srow, 'r') or die("ERR_OPEN_FILE");
$smstext = trim(fgets($smsfile,4096));
$smstext = iconv("UTF-8","Windows-1251",$smstext);
fclose($smsfile);
$uta = date('YmdHis');
$filehfp = $msgtosend.'/'.$uta.$smscount.'.dat';
$filehfpnew = $msgtosend.'/'.$uta.$smscount.'.msg';
$hfptext = 'to=' . $qru_id . ',speed=0,askreq=1,resend=3' . "\n" . $smstext . "\n";
file_put_contents($filehfp, $hfptext);
rename($filehfp, $filehfpnew);
unlink($dirqru.'/'.$srow);
}
} else { // Если в директории ничего нет
$qru_text = iconv("UTF-8","Windows-1251",'No msg!');
$uta = date('YmdHis');
$filehfp = $msgtosend.'/'.$uta.'.dat';
$filehfpnew = $msgtosend.'/'.$uta.'.msg';
$hfptext = 'to=' . $qru_id . ',speed=0,askreq=1,resend=3' . "\n" . $qru_text . "\n";
file_put_contents($filehfp, $hfptext);
rename($filehfp, $filehfpnew);
}
} else { // Если директория не существует
$qru_text = iconv("UTF-8","Windows-1251",'No msg!');
$uta = date('YmdHis');
$filehfp = $msgtosend.'/'.$uta.'.dat';
$filehfpnew = $msgtosend.'/'.$uta.'.msg';
$hfptext = 'to=' . $qru_id . ',speed=0,askreq=1,resend=3' . "\n" . $qru_text . "\n";
file_put_contents($filehfp, $hfptext);
rename($filehfp, $filehfpnew);
}
}
// STOP If message conteins 'QRU?'
} // STOP If message for our ID
} // STOP REC-containing files
}
}
echo "\n\n";
?>




























