再也无法忍受 Windows 自带(拉中之拉的)邮件客户端——更新频率比苹果 Mail 还慢,有幸下载到的邮件还有 95% 的几率无法自动正常显示

于是萌生了使用第三方邮件客户端的想法,但是几经搜索都没有找到满意的,手机 QQ 邮箱还有广告推送

因为平时只有接收验证码/看游戏推广的时候用到邮件,所以需求很简单:

  • 能接收邮件并正常显示
    • “能接收邮件”具体是指迅速下载邮件,而不是给我一个卡住的进度条/转转转的菊花圈(验证码都失效了还没下载完)
  • 支持多个邮箱登录
  • 甚至不需要发邮件功能

最好是这样的一个系统:WebMail 有单独的账户系统,登录 WebMail 的自带账户后链接多个邮箱获取邮件(并不是像 QQ 网页邮箱那种直接使用邮箱账号登录)

网上有很多开源自托管的 WebMail 服务,权衡搭建维护复杂度后决定尝试 RainLoop 和 Cypht,最终选择了Cypht,因为 RainLoop 需要直接使用邮箱账号登录,没有自带的账户系统

下文将展示如何在 Debian 10 下无域名搭建 RainLoop 和 Cypht

环境

  • Debian 10

参考

步骤

以下指令均在 root 用户下执行,其他用户请酌情添加 sudo

RainLoop

下文将安装 RainLoop 标准版,标准版不能用于商业用途,可以个人非盈利使用

环境安装

RainLoop 基于 PHP,需要安装 PHP(>= 5.4) 环境,执行

apt install php7.3 php7.3-dev php7.3-fpm php7.3-curl nginx unzip

检查 php-fpm 是否开启

获取并解压 RainLoop

执行

wget http://www.rainloop.net/repository/webmail/rainloop-latest.zip
mkdir /var/www/rainloop
unzip rainloop-latest.zip -d /var/www/rainloop

配置权限

执行

cd /var/www/rainloop
find . -type d -exec chmod 755 {} \;
find . -type f -exec chmod 644 {} \;
chown -R www-data:www-data .

这里默认 Web 服务器用户为 www-data(Debian 包管理安装的 nginx 均使用此用户),如果 Web 服务器使用了其他用户,则修改为对应用户

配置 Web 服务器

  1. /etc/nginx/sites-available 下新建配置文件 rainloop,写入以下内容
    server {
            listen 80 default_server;
    
            root /var/www/rainloop;
    
            index index.php;
    
            server_name [服务器 IP];
    
            location / {
                    try_files $uri $uri/ =404;
            }
    
            location ~ \.php$ {
            include snippets/fastcgi-php.conf;
            fastcgi_pass unix:/run/php/php7.0-fpm.sock;
            }
            
        location ^~ /data {
            deny all;
        }
    }
    
  2. 软连接到 /etc/nginx/sites-enabled
    ln -s /etc/nginx/sites-available/rainloop /etc/nginx/sites-enabled/rainloop
  3. 启动 Web 服务器
    nginx -t
    # 无误后
    nginx -s reload

浏览器访问 IP 地址进入 RainLoop

Cypht

由于本地安装 Cypht 的步骤非常繁琐,所以这里选择 docker

安装 docker / docker-compose

执行

# docker
curl -sSL https://get.docker.com | sh
# docker-compose
curl -L "https://github.com/docker/compose/releases/download/1.29.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
chmod +x /usr/local/bin/docker-compose
ln -s /usr/local/bin/docker-compose /usr/bin/docker-compose

编辑 docker-compose.yml

新建 cypht 目录,新建 docker-compose.yml

mkdir cypht
cd cypht
vim docker-compose.yml

写入以下内容

version: '3'
services:
  db:
    image: mariadb:10
    volumes:
      - ./db:/var/lib/mysql
    environment:
      - MYSQL_ROOT_PASSWORD=[MYSQL 的 root 密码]
      - MYSQL_DATABASE=cypht
      - MYSQL_USER=cypht
      - MYSQL_PASSWORD=[MYSQL 的 cypht 密码]
  cypht:
    image: sailfrog/cypht-docker:latest
    volumes:
      - ./cypht/users:/var/lib/hm3/users
    ports:
      - "80:80"
    environment:
      - CYPHT_AUTH_USERNAME=[cypht 登录账户名称]
      - CYPHT_AUTH_PASSWORD=[cypht 登录账户密码]
      - CYPHT_DB_CONNECTION_TYPE=host
      - CYPHT_DB_HOST=db
      - CYPHT_DB_NAME=cypht
      - CYPHT_DB_USER=cypht
      - CYPHT_DB_PASS=[MYSQL 的 cypht 密码]
      - CYPHT_SESSION_TYPE=DB

启动 Cypht

执行

docker-compose pull
# 无误后
docker-compose up -d

浏览器访问 IP 地址进入 Cypht

Continue reading “自托管 WebMail 的选择 – RainLoop 和 Cypht”

实际上是一个找规律的题(以下题解表达得很差,仅适合本人阅读)

解法思想对应官方题解中的行扫描——N 型排列后一行一行地将字符加入数组——但是比官方解法多了一个变量:官方解法中一个一个添加字符,这里是两个两个添加

以 Leetcode 示例为例,设字符串 s 为 PAYPALISHIRING,行数为 numRows(后文简称 n),见下图

首先把 N 型排列写出来,可以发现:排列看似是 N 型,实际上是斜 V 字型的循环(图中的蓝色字符),于是找到循环数,得出循环数公式: nextIndex = (n – 1) * 2

得到循环数,也就得到了图中绿色背景字符的规律:设每行首个字符的下标为 i,绿色背景字符的下标偏移量为 k,则 k = i + nextIndex

对于黄色背景的字符,可以发现:设每行首个字符的下标为 i,黄色背景字符的下标偏移量为 j,则 j = nextIndexi * 2

最终将每行的字符按规律加入数组即可:每行的前两个字符下标分别为 i + ji + k,之后分别累加循环数 nextIndex

C# 题解

public class Solution {
    public string Convert(string s, int numRows) {
        int n = s.Length, nextIndex = 2 * (numRows - 1); //长度和循环数
    if (n == 1 || numRows == 1 || n <= numRows) return s; // 字符串长度小于等于行数时直接返回原串

    StringBuilder sb = new StringBuilder(); // 使用 StringBuilder 防坑

    for (int i = 0, cnt = 0; i < numRows; i++, cnt += 2) { // cnt 累加2,即 i * 2
        sb.Append(s[i]); // 每行第一个字符
        int step = nextIndex - cnt; // 黄色背景字符的下标偏移量
        for (int j = i + step, k = i + nextIndex; j <= n - 1; j += nextIndex, k += nextIndex) {
            if (step != 0 && step != nextIndex) //第一行和最后一行不添加黄色背景字符
                sb.Append(s[j]);
            if(k <= n - 1) // 循环退出条件是黄色背景字符,防止绿色背景字符下标溢出
                sb.Append(s[k]);
        }
    }

    return sb.ToString();
    }
}

Continue reading “Leetcode 6 – Z 字形变换”