IP发生变化时邮件自动通知的实现

因为我们的办公室在南院,所以做数值模拟工作需要在服务器上跑代码,而登录服务器就离不开它的IP地址。这件事是在11月12日因为封校时,汤中正要我帮忙开启服务器并查询IP地址给他开始考虑的。我解决这个问题的思路是,写一个脚本,第一步获取IP地址,存储在服务器上的脚本文件中,每隔一段时间检测一下当前IP地址和脚本中的IP地址是否一致,如果不一致则通过命令自动向使用者发邮件告知新的IP地址。这样就不必请人帮忙查询IP地址了。本文就是介绍邮箱配置和编写脚本的。

软件介绍

s-nail

参考文章使用mailx在控制台发送邮件,本文仅引用一部分。

mail命令最早出现在1971年问世的第一版Unix上,当时只是用于向同一台计算机上的其他用户发送邮件。在后来的Unix版本中mail扩展了发送远程邮件的功能。

1978年在BSD Unix上(Unix的一个主要分支)出现了另一个邮件程序Berkeley Mail,它也使用mail命令,并在后来代替了原Unix的mail。 在1987年发布的Unix版本上出现了Berkeley Mail的衍生版本mailx,该程序使用命令mailx。

由于Unix长期处于闭源状态,Linux用户无法使用Unix的mailx程序,于是出现了基于Berkeley Mail的开源版本nail,后改名为Heirloom mailx。Heirloom mailx与Berkeley Mail一样使用mail命令,并扩展了很多功能,如内置的POP3、IMAP、SMTP支持。Heirloom mailx尽可能保持与mailx的使用体验一致,所以也添加了mailx命令,但它只是mail的符号链接。

以前各Linux发行版上的mailx软件包基本都是打包自Heirloom mailx。Heirloom mailx 的更新后来逐渐停滞,又出现了Heirloom mailx的分支s-nail。目前各发行版已经用s-nail取代了Heirloom mailx,包名一般是s-nail,提供mail和mailx命令,使用体验与Heirloom mailx基本一致。 s-nail将来的v15版本将做出不向后兼容的巨大改变,且s-nail欲更名为s-mailx。

postfix

postfix是Wietse Venema在IBM的GPL协议之下开发的MTA(邮件传输代理)软件。postfix是Wietse Venema想要为使用最广泛的sendmail提供替代品的一个尝试。在Internet世界中,大部分的电子邮件都是通过sendmail来投递的,大约有100万用户使用sendmail,每天投递上亿封邮件。这真是一个让人吃惊的数字。Postfix试图更快、更容易管理、更安全,同时还与sendmail保持足够的兼容性。

安装软件

1
sudo pacman -S s-nail postfix

配置邮件系统

安装上s-nailpostfix 后,服务器已经具备发送邮件的能力。本身s-nail支持smtp,pop,imap等邮件协议,如果单独发送外网邮件这已经足够了。但作为一个邮件服务器,postfix提供收发邮件的能力,后面介绍发送邮件的方法。

安装两个软件后,我们需要实现向外网发送邮件。但是遇到了一系列的问题,这里不得不说本以为网易163邮箱是好用的,但是其为了推广自家的邮件客户端,虽然能开通imap, pop3,smtp 但是在命令s-nail中只能使用smtp发外网邮件,收件是不行的,这导致我一直认为是我配置的不对,真是服了这老6!同时换用outlook邮件测试,其发件收件都无法完成,偶然只成功发了一封邮件,但是时间是相差了8个小时,我意识对于这个全球系统它考虑了时差因为我们正处于+8区,希望微软能够尽快修复这个bug,因此其也是不可用的。最后测试通过是sina.cnqq.com两个邮箱,其收发都是完美的。

配置s-nail

其全局配置文件位于/etc/mail.rc,但是为了安全起见不建议修改这个文件,这里我参考s-nail archlinux wiki得到设置方法,最佳方案是建立文件~/.mailrc 按下文配置,由于网上的文章都比较老旧,这里不打算再列出一些文章了,因为现在配置方式发生了变化,本文直接给出方法。

  1. 默认邮件配置(以QQ邮箱为例)
~/.mailrc
1
2
3
4
5
6
7
8
9
set v15-compat
set imap-keepalive=240
set imap-cache=~/.imap_cache
set smtp-auth=login
set smtp-use-starttls
set from='888888888@qq.com'
set mta='smtp://888888888:aaaaalebbbbbbbdf@smtp.qq.com'
#set inbox="pop3s://888888888:aaaaalebbbbbbbdf@pop.qq.com"
set inbox="imaps://888888888:aaaaalebbbbbbbdf@imap.qq.com"
  1. 多个邮件配置(以QQ邮箱+163邮箱为例~/.mailrc)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
account qq.com {
set v15-compat
set imap-keepalive=240
set imap-cache=~/.imap_cache
localopts yes
set smtp-auth=login
set smtp-use-starttls
set from='888888888@qq.com'
set mta='smtp://888888888:aaaaalebbbbbbbdf@smtp.qq.com'
# set inbox="pop3s://888888888:aaaaalebbbbbbbdf@pop.qq.com"
set inbox="imaps://888888888:aaaaalebbbbbbbdf@imap.qq.com"
}

account 163.com {
localopts yes
set smtp-auth=login
set smtp-use-starttls
set mta='smtp://163163163:aaaaalebbbbbbbdf@smtp.163.com'
set from='163163163@163.com'
}

由于前述的原因,关于163邮箱我只配置了发送smtp,测试收件imap和pop3不成功。但是qq邮箱均测试成功,所以关于qq邮箱写的比较完整。 在上面的配置中,888888888 是你的QQ号,aaaaalebbbbbbbdf是邮箱的授权码,这个登录网页邮箱通过设置可以获取。具体方法参考 如何打开POP3/SMTP/IMAP功能?,对于网易163邮箱同理也可以取得授权码。

使用s-nail

  1. 接收邮件

这点其实是使用的s-nail提供的mail命令,如果已经按前述配置好了imappop3由在终端直接输入mail便可以读取邮件了。如下图所示

终端执行mail命令
  1. 不配置邮箱,直接发局域网邮件
1
echo "服务器IP地址发生变动,新IP地址为 172.16.202.69" | mail -s "IP变动通知" 20222114xxx@mail.bnu.edu.cn

由于校园邮箱是由网易提供的企业邮箱,同时服务器位于校园内,因此如果仅通知IP地址的变动的话,直接根据学生编号向其发送新的IP地址即可。

  1. 发送邮件
  • 执行mail命令,传入收件人参数
1
mail `laoliu@163.com`
  • 多个收件人用空格分开,每个参数对应一个收件人,也可以添加名字,还可以用配置文件里的别名
1
mail `laoliu@163.com` `xiaogou@outlook.com` zhangsan
  • 编写邮件

mailx默认从标准输入读取邮件。在终端输入mail命令并传入收件人参数后按回车,即可进入mail的交互界面。首先会提示输入邮件主题,直接按回车可跳过。接着会自动生成To一行,即收件人。然后就可以写正文。

正文写完后在新的一行按ctrl+D即可结束输入。此时会自动生成邮件标头,并询问是否发送邮件。输入yes或y发送邮件,直接按回车重新编辑。 如果邮件发送失败,会在用户根目录生成“dead.letter”文件,包含邮件正文和日期。

1
2
3
4
5
6
7
8
9
10
11
[user@host]$ mail zhangsan@qq.com
Subject: Hello
To: zhangsan@qq.com
Hello, Zhangsan.
^D
-------
Envelope contains:
From: Lisi <lisi@qq.com>
To: zhangsan@qq.com
Subject: Hello
Send this message [yes/no, empty: recompose]?
  • 使用管道或重定向

如果使用管道或者输入重定向,mail将不会进入交互页面,而是直接发送邮件。

1
2
3
mail lisi@qq.com < ~/letter
mail lisi@qq.com <<< Hello
echo "$PATH" | mail lisi@qq.com
  • 添加标题
1
mail -s "标题" zhangsan@qq.com
  • 添加附件
1
mail -a ~/file lisi@qq.com

注意: 一定要把选项加在收件人的前面,否则会把选项解释为收件人。

  • 常用选项解释
常用选项 解释
-v 显示发件过程的详细信息
-a 添加附件
-b 添加密送
-c 添加抄送
-s 添加标题
-S 作用与配置文件中的set相同
-h 查看帮助

如果需要更多解释,请参考mailman手册。

1
man mail

  • 安装man手册

在处理这个邮件的时候,我才发现自己安装的archlinux太过纯净了,没有安装这个手册,所以现在安装上man手册。参考man page(简体中文)

1
sudo pacman -S man-db man-pages mang-pages-zh_cn

IP自动邮件通知脚本

由于时间(2022年 11月 20日 星期日 01:14:28 CST)太晚了,今天没有完成脚本的编写工作,此位置暂时保留。仅列出一段获取IP地址的脚本内容,如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#! /bin/sh
#
# 脚本名称: amip.sh
# 名称解释:auto mail ip
# Copyright (C) 2022 feng <feng@archlinux>
#
# Distributed under terms of the MIT license.
#
IPIfo=$(ip addr |grep inet |grep -v inet6 |grep -v '127.0.0.1')
TheIP=$(echo $IPIfo |awk '{print $2}' |awk -F '[/]' '{print $1}')
TheName=$(hostnamectl hostname)
EmailToList=(
"fengzhenhua@mail.bnu.edu.cn"
"zhilongzhao@mail.bnu.edu.cn"
"qingpingliu@mail.bnu.edu.cn"
)
OldIP="172.23.28.228"
if [ ! $OldIP == $TheIP ]; then
sed -i "s/^OldIP.*$/OldIP=\"${TheIP}\"/g" $0
for emt in ${EmailToList[@]}; do
echo "$(date) 主机"$TheName"的IP发生变动,新IP为: $TheIP" | mail --account=163 -s ""$TheName"主机IP变动通知" $emt
done
fi

脚本还有优化的空间,如要实现服务器自动检测IP地址,则需要设置定时执行任务,并部署到服务器上设置为自动启动。定时任务设置参考 Linux crontab 命令 关于设置开机启动请参考 systemctl 命令完全指南 由于本工作不是当前刚需,所以暂缓完善[2022年11月20日]