第13章 邮件代理模块

本章将说明Nginx官方提供的一系列邮件模块,这些邮件模块配合Nginx事件框架共同构建了支持POP3、SMTP、IMAP这3种协议的邮件代理服务器,它们把邮件代理服务器的主要功能抽象成一个类似于HTTP框架的邮件框架,以灵活地支持Nginx扩展更多的邮件协议,而POP3、SMTP、IMAP模块将作为普通的邮件模块使用这套框架。作为邮件代理服务器的Nginx虽然也访问上游服务器,但由于它不使用HTTP框架,所以无法使用第12章介绍的upstream机制,然而“邮件代理”其实同样具有部分的反向代理功能,本章13.7节介绍的透传TCP部分其实也有点像一个简化版的upstream机制。

本章首先介绍邮件代理功能到底做了哪些事情,接下来会分析Nginx如何实现邮件代理功能。实际上,本章更像是第10章~第12章的简化版本,所以在本章中将不会再次描述曾经介绍过的如何异步地、无阻塞地提供服务,以及如何使用epoll、定时器等事件框架。读者也应当熟悉Nginx的这套设计方法了,因此本章仅会描述邮件模块的主要阶段,不会深入细节。另外,本章也不会详细说明POP3、SMTP、IMAP,因为Nginx并非真正的邮件服务器。本章的重点在于了解邮件代理服务器的使用方法,以及应该如何扩展邮件代理模块的功能,同时了解通过邮件模块继续熟悉Nginx事件框架的用法,继而熟悉如何利用它开发高性能服务器。

13.1 邮件代理服务器的功能

在第8章中介绍过邮件模块,它提供了邮件代理服务器的功能。什么是邮件代理服务器?顾名思义,它不会提供实际的邮件服务器功能,而是把客户端的请求代理到上游的邮件服务器中。那么,客户端为何不直接访问真正的邮件服务器,反而多此一举地访问邮件代理服务器呢?原因可以在后续章节描述的Nginx实现中找到,其中最重要的是Nginx并不是简单地透传邮件协议到上游,它还有一个认证的过程,如图13-1所示。

从图13-1中可以看出,Nginx在与下游客户端交互过程中,还会访问认证服务器,只有认证服务器通过了并且被告知Nginx上游的邮件服务器地址后,Nginx才会向上游的邮件服务器发起通信请求。同时,Nginx可以解析客户端的协议获得必要的信息,接下来它还可以根据客户端发来的信息快速、独立地与邮件服务器做简单的认证交互,之后才会开始在上、下游之间透传TCP流。这些行为都意味着Nginx的高并发特性将会降低上游邮件服务器的并发压力。

第13章 邮件代理模块 - 图1

图 13-1 Nginx在邮件代理场景中的位置

Nginx与下游客户端、上游邮件服务器间都是使用邮件协议,而与认证服务器之间却是通过类似HTTP的形式进行通信的。例如,发往认证服务器的请求如下所示:


GET/auth HTTP/1.0

Host:auth.server.hostname

Auth-Method:plain

Auth-User:user

Auth-Pass:password

Auth-Protocol:imap

Auth-Login-Attempt:1

Client-IP:192.168.1.1


而认证服务器会返回最常见的成功响应,即类似下面的字符流:


HTTP/1.0 200 OK

Auth-Status:OK

Auth-Server:192.168.1.10

Auth-Port:110

Auth-User:newname


当然,认证服务器的返回要复杂得多。由于本章既不会介绍认证服务器如何实现,也不会介绍上游的邮件服务器如何实现,所以对协议部分不会继续深入介绍。

一般情况下,客户端发起的邮件请求在经过Nginx这个邮件代理服务器后,网络通信过程如图13-2所示。

第13章 邮件代理模块 - 图2

图 13-2 邮件代理功能的示意序列图

从网络通信的角度来看,Nginx实现邮件代理功能时会把一个请求分为以下4个阶段。

❑接收并解析客户端初始请求的阶段。

❑向认证服务器验证请求合法性,并获取上游邮件服务器地址的阶段。

❑Nginx根据用户信息多次与上游邮件服务器交互验证合法性的阶段。

❑Nginx在客户端与上游邮件服务器间纯粹透传TCP流的阶段。

由此可以了解到,这些Nginx邮件模块的目的非常明确,就是使用事件框架在大量并发连接下高效地处理这4个阶段的请求。

为了让读者对邮件代理服务器有直观的认识,下面再来看看nginx.conf配置文件。邮件模块定义的nginx.conf配置文件与HTTP模块非常相似。例如,常见的配置可能就像下面的这段配置一样。


mail{

//邮件认证服务器的访问URL

auth_http IP:PORT/auth.php;

//当透传上、下游间的TCP流时,每个请求所使用的内存缓冲区大小

proxy_buffer 4k;

server{

/对于POP3协议,通常都是监听110端口。POP3协议接收初始客户端请求的缓冲区固定为128字节,配置文件中无法设置/

listen 110;

protocol pop3;

proxy on;

}

server{

//对于IMAP,通常都是监听143端口

listen 143;

protocol imap;

//设置接收初始客户端请求的缓冲区大小

imap_client_buffer 4k;

proxy on;

}

server{

//对于SMTP,通常都是监听25端口

listen 25;

protocol smtp;

proxy on;

//设置接收初始客户端请求的缓冲区大小

smtp_client_buffer 4k;

}

}


mail{}块下的配置项将会被本章介绍的邮件模块所使用。就像HTTP模块中的配置一样,直属于mail{}块下的配置称为main级别的配置,而在server{}块下的配置则称为svr配置(不使用HTTP,故没有loc级别的配置)。