Краткое описание почтового клиента electronic-vue

Node.js Vue.js HTML Electron

О проекте

Это мой дипломный проект (2018), почтовый клиент

Включая отправку и получение электронных писем, адресную книгу, вход в систему с несколькими учетными записями, локальное хранилище данных и другие функции.

гитхаб:GitHub.com/oooooooo Эван/VM…

Используемые связанные модули

  • Построение проекта с помощью electronic-vue vue-cli
  • Получение сообщений с помощью модуля node-imap
  • Используйте element-ui в качестве основы стиля
  • Использовать lowdb как локальное хранилище данных
  • Ручка, кодирующая с iconv-lite, цитируемым для печати, UTF8 и т. Д.
  • Сделайте расширенный текстовый редактор с помощью vue-quill-editor

Введение в эксплуатацию

npm run dev    # 调试运行,localhost:9080

npm run build  # 打包,安装包在build目录

Скриншот страницы

收件箱

邮箱详情

写邮件

通讯录

каталог проекта

Самая внешняя структура создается электронно-вью, которая в основном зависит от структуры src.

─ src
 ├── main
 │  ├── index.js                         #主进程,创建渲染进程
 ├── models                              #定义模型,用于封装对象
 ├── renrender                           #渲染进程,里面就是一个vue项目目录
 │  ├── common                           #一些重要的js函数与公共样式
 │      ├── javascript
 │          ├── cache.js                 #硬盘存取相关函数
 │          ├── config.js                #存放配置及正则表达式
 │          ├── getEmail.js              #获取email的函数
 │          ├── parseEmail.js            #解析email的函数
 │          ├── sendEmail.js             #发送email的函数
 │      ├── style
 │  ├── components                       #存放组件
 │  ├── pages                            #存放页面
 │  ├── router                           #路由
 │  ├── store                            #vuex的store相关文件
 │  ├── app.vue                          #vue页面最外层结构
 │  ├── main.js                          #vue项目入口
 ├── index.ejs                           #electron页面入口

процесс развития

Об электроне и vue

Electron объединяет chromium и nodejs в одну и ту же среду выполнения и может использовать html, css и javascript для создания кроссплатформенных настольных приложений. Проще говоря, когда мы пишем веб-страницы, мы также можем вызвать API-интерфейс nodejs (например, вызвать модуль fs для сохранения данных на компьютере), а затем электрон поможет нам упаковать его в кроссплатформенное настольное приложение. Vue — это один из основных фреймворков mvvm в настоящее время. Я не буду его здесь представлять. Он использует vuex, маршрутизатор и т. д. Если вы не понимаете, вам нужно понять его, прежде чем вы сможете понять проект.

Этот проект использует vue-vli для инициализации electronic-vue, что удобно для разработки

vue init simulatedgreg/electron-vue Vmail

初始化选项

Вариант упаковки — электронный сборщик, этот инструмент может напрямую упаковывать установочный пакет, а электронный упаковщик упаковывается в исполняемый файл.

Декомпозиция идеи проекта

Основной частью проекта является почта, и есть четыре важных шага: получить и проанализировать почту, сохранить почту, отобразить почту и отправить почту. Получение и отправка электронных писем анализируются в соответствии с протоколом электронной почты.

Привлекать и анализировать электронные письма

node-imapЭта библиотека очень хороша, используйте ее

node-imapЭта библиотека содержит две функции, а также поддерживает множество различных параметров, с которыми можно ознакомиться на github самостоятельно.

Далее основное внимание уделяется анализу электронной почты.

Электронное письмо состоит из двух частей: заголовка и тела. Формат заголовка электронной почты в основном одинаков, а формат тела электронной почты различается, поскольку существует множество типов, таких как: обычный текст, html-страницы, включая вложения и т. д.Первый шаг — увидетьContent-Type

  1. текст, в основном text/html и text/plain, содержимое необходимо декодировать с помощью Content-Transfer-Encoding, распространенными кодировками передачи являются base64 и кавычки-печать
  2. многочастный, делится на смешанный, альтернативный и родственный. multipart имеет граничный разделитель, который делит тело сообщения на разные сегменты.
    • смешанный тип с вложениями
    • альтернатива - это тип, в котором существует как обычный текст, так и гипертекст.
    • связанный - это встроенный тип ресурса, например, содержимое в формате html, но в html есть изображения, извлеките изображения и отправьте их в виде вложений.
  3. Изображение, приложение, обычно формат, который появляется в приложении

второй шагboundary

Только составной тип имеет границу, потому что этот тип более сложен и его необходимо анализировать с сегментацией границ.

Content-Type: multipart/mixed;
  boundary="----=_NextPart_5A640E3E_0AF97620_651579F6"

Граница здесь представляет собой строку символов, но разделение происходит не непосредственно по границе, а по родительскому сегменту и дочернему сегменту.

Родительский сегмент:'--' + boundary + '--'

Подраздел:'--' + boundary

Из того, что я наблюдал, родительский сегмент появляется только 0 или 1 раз и находится в последней позиции (вероятно, у меня ограниченные типы почты), поэтому содержимое является первым элементом разделенного массива:emailText = emailText.split(fatherBoundary)[0].trim()Подразделы делят содержимое на разные разделы, и каждый подраздел нужно перерабатывать отдельно, потому что у него тоже есть своиContent-typeа такжеboundary, поэтому сообщение может появиться в двух разныхboundary

Третий этап анализаЕсли сегмент разделен html или другими аксессуарами и тому подобным, непосредственно из кодировки и парсинга charset; если все же составной тип, то то же самое мышление снова парсится (о разрешении кода скажу ниже)

В следующем примере (удаленная часть не нужна):

From: "=?gb18030?B?amlhbmJvKw==?=" <490549111@qq.com>
To: "=?gb18030?B?amlhbmJvKw==?=" <635638508@qq.com>
Subject: 123
Content-Type: multipart/mixed;
  boundary="----=_NextPart_5A5F05FC_0A84FD10_42CF1A15"
Content-Transfer-Encoding: 8Bit
Date: Wed, 17 Jan 2018 16:14:52 +0800

This is a multi-part message in MIME format.

------=_NextPart_5A5F05FC_0A84FD10_42CF1A15
Content-Type: multipart/alternative;
  boundary="----=_NextPart_5A5F05FC_0A84FD10_3247BB56";

------=_NextPart_5A5F05FC_0A84FD10_3247BB56
Content-Type: text/plain;
  charset="gb18030"
Content-Transfer-Encoding: base64

MTINCjM=

------=_NextPart_5A5F05FC_0A84FD10_3247BB56
Content-Type: text/html;
  charset="gb18030"
Content-Transfer-Encoding: base64

PGRpdj4xMjwvZGl2PjxkaXY+MzwvZGl2Pg==

------=_NextPart_5A5F05FC_0A84FD10_3247BB56--

------=_NextPart_5A5F05FC_0A84FD10_42CF1A15
Content-Type: application/octet-stream;
  charset="gb18030";
  name="=?gb18030?B?08q8/s/qx+kucG5n?="
Content-Disposition: attachment; filename="=?gb18030?B?08q8/s/qx+kucG5n?="
Content-Transfer-Encoding: base64

iVBORw0KGgoAAAANSUhEUgAAA2QAAAHRCAIAAACKEu1wAAAAAXNSR0IArs4c6QAAA...(很长,省略)

------=_NextPart_5A5F05FC_0A84FD10_42CF1A15--

анализировать:

  1. Тип содержимогоmultipart/mixed, указывая, что тип вложения включен
  2. Родительский сегмент появляется в конце, и разделенный массив может занять первый элемент.
  3. Согласно сегментации подсегментации, сегмент имеет свою собственную границу, тип контента и Charset.
    1. Первый абзац представляет собой альтернативное небольшое электронное письмо, содержащее как обычный текст, так и гипертекст. Затем разделите его по границе
      1. После синтаксического анализа текстовое содержимое12\r\n3
      2. После синтаксического анализа гипертекстовое содержимое может быть<div>12</div><div>3</div>
    2. Второй абзац — вложение типа приложения, судя по кодировке и разбору кодировки имя файла邮件详情.png

Вопросы, о которых следует помнить при написании

  1. Обнаружен Content-type какmultipart/related;type="multipart/alternative";boundary="----=_NextPart_5A6951CD_6F185580_3879981A, это надо считать родственным, а не альтернативным, по комплексному
  2. Обратите внимание, что правила синтаксического анализа связанных типов и смешанных типов одинаковы.
  3. Некоторые электронные письма имеют неполные значения (например, отсутствие кодировки), и вам необходимо установить значения по умолчанию.
  4. Ошибка синтаксического анализа значения base64 связана с тем, что base64 имеет новую строку и ее необходимо удалить.

Хранилище электронной почты

── attr   #有邮件uid等简单信息
── body
   ├──attachment   #附件
   ├──bodyHtml      #超文本
   ├──bodyText      #纯文本
── emailText        #完整的邮件文本
── header           #头部信息

Content-typeПреобразование повторно сохраняется, в противном случае, если вы хотите судить о разных типах различной обработки во время отображения. Очевидно, хранить предобработку лучше

  1. Если тип HTML, BodyHTML отдельно сохраняет файл, а значение bodyhtml - это путь к файлу. Здесь вам нужно рассмотреть HTML не является полной страницей, а фрагмент.
  2. Если это смешанный тип, сохраните вложение в отдельном файле, а также сохраните его как путь к файлу.
  3. Что касается альтернативных и родственных, здесь нет необходимости рассматривать их отдельно. Поскольку альтернативой является сосуществование обычного текста и гипертекста, то есть повторение, гипертекст — это фрагмент html, включая формат, а обычный текст содержит только текст, просто сохраните гипертекст; связанный — это то же самое, что и правило смешанного синтаксического анализа, и ему необходимо указывать ресурсы Синтезируйте полный html и сохраните html отдельно.
if (contentType.match(htmlTypeReg)) {...}  //单独存储html
else if (contentType.match(mixedMultipart)) {...} // 单独存储附件
if (!contentType.match(htmlTypeReg)) {...}  //非htmlTypeReg也进行单独存储html

показать почту

Хранилище очень регулярное, поэтому логика очень понятна при отображении.

  1. bodyHtml начинается с.htmlВ конце это HTML-путь, который импортируется с SRC веб-просмотра
  2. bodyHtml не является путем, вставьте html-фрагмент
  3. Без bodyHtml вставьте bodyText
  4. Если есть вложение, оно будет отображаться, а если вложения нет, оно отображаться не будет.
if (bodyHtml.indexOf(HTML) && bodyHtml.indexOf(HTML) + HTML.length === bodyHtml.length) {...} //html是路径
else if (bodyHtml) {...} //html不是路径
else {...} //没有html,只能取bodyText
if (detail.body.attachment && detail.body.attachment.length) {...} //显示附件

отправить электронное письмо

Для отправки почты есть stmp (Simple Mail Transfer Protocol), а на github есть готовые и зрелыеnodemailer, будь то отправка html или вложений, очень просто.

проблемы развития

кодирование

Первое, что получает почта, — это поток, который требует кодировки для преобразования в исходную строку. Я использую декодирование gb18030 В кодировке серии gb можете разобраться сами.Напомню вкратце:сначала были только ascii.Китай хотел отображать китайский,поэтому были gb2312,gbk и т.д.и потихоньку добавляли традиционные символы из упрощенного китайского , Последняя обновленная версия - gb18030, поэтому это серия gb. Просто используйте gb18030 напрямую, потому что она обратно совместима.

Кажется, что gb18030 или utf-8 можно использовать для анализа исходного потока, потому что каждая часть была преобразована в код ascii с кодировкой base64 или другой.

From: "=?gb18030?B?amlhbmJvKw==?=" <490549111@qq.com>

Приведенная выше строка отражает две вещи: 1. Набор символов gb18030, то есть это письмо закодировано gb18030 2. B означаетbase64, следующие символы закодированы с помощью base64

Идея синтаксического анализа состоит в том, чтобы сначала использовать base64 для преобразования в буфер, а затем использовать набор символов gb18030 для преобразования в строку Способ разбора такойiconv.decode(iconv.encode('amlhbmJvKw==?=','base64'),'gb18030')

From: =?UTF-8?B?6Zi/6YeM5LqR?= <system@notice.aliyun.com>

Точно так же это кодировка base64 кодировки utf-8. Способ разбора такойiconv.decode(iconv.encode('B?6Zi/6YeM5LqR?=','base64'),'utf-8')

iconv.decode(iconv.encode('阿里郎阿里云','gb18030'),'utf-8')
iconv.decode(iconv.encode('6Zi/6YeM6YOO6Zi/6YeM5LqR','base64'),'gb18030')

Если смешать gb18030 и utf-8, будут искажены символы, потому что их наборы символов различны, а символы, представленные одной и той же кодировкой, различны.

Первая строка вывода выше�����ɰ�����. вторая линия выпуска闃块噷閮庨樋閲屼簯

Для содержимого в граничном сегменте, например:

------=_NextPart_5A640E3E_0AF97620_02509F49
Content-Type: text/plain;
  charset="gb18030"
Content-Transfer-Encoding: base64

cXdlenhj

В нем четко прописаны набор символов и кодировка передачи, а простой текст можно получить путем разбора по его правилам.qwezxc

Использование node-imap, связанного с imap

使用node-imap模块,一方面是较灵活,另一方面是可以同步状态。最大的问题是发现同步状态失败,根据文档下面这样就可以标记邮件已读,但是怎么都失败。 .可能是支持性不够

imap.openBox('INBOX', false, cb);       //openBox不能是readOnly,置false
let f = imap.fetch(results, { bodies: '', markSeen: true }); //markSeen为true

Больше документации API, параметров и многого другого, но многие результаты противоречивы, чтобы наблюдать за несколькими тестами, выяснить, какое использование API.

  mainWindow = new BrowserWindow({
    height: 563,
    width: 1000,
    useContentSize: true,
    autoHideMenuBar: true,
    title: 'Vmail',
    disableAutoHideCursor: true,
    frame: false // 没有边框
  })

<header style="-webkit-app-region: drag">

<div class="refresh fl" style="-webkit-app-region: no-drag">

const { remote } = require('electron')
...
data () {
  return {
    isFullScreen: false  //当前是否全屏状态
  }
},
mounted () {
  window.addEventListener('resize', () => {  //当resize时检测是否全屏
    this.isFullScreen = remote.getCurrentWindow().isMaximized()
  })
},
methods: {
  close () {
    remote.getCurrentWindow().close()  //点击关闭,停止渲染进程
  },
  minimize () {
    remote.getCurrentWindow().minimize()  //窗口最小化
  },
  full () {
    const browserWindow = remote.getCurrentWindow()  //全屏toggle
    if (browserWindow.isMaximized()) {
      browserWindow.unmaximize()
      this.isFullScreen = false
    } else {
      browserWindow.maximize()
      this.isFullScreen = true
    }
  },

Есть полноэкранный судbrowserWindow.isFullScreen(), обнаружил, что двойной щелчок на полосе перетаскивания не может правильно вернуться в полноэкранный режим,browserWindow.isMaximized()можно правильно судить.

Что касается мониторинга событий, используйте addEventListener, а не onresize, потому что resize используется в нескольких местах, а onresize перезапишет друг друга.

Пакет

Проект упакован с помощью электронного компоновщика, и для первой сборки необходимо загрузить зависимости. Поскольку ресурсы находятся за стеной, вам придется перелезть через стену, иначе будет сообщено об ошибке. Также можно попробовать скачать его вручную, и скачать соответствующий файл по подсказкам в командной строке.

npm должен настроить зеркало, файл конфигурации~/.npmrc

registry=https://registry.npm.taobao.org
sass_binary_site=https://npm.taobao.org/mirrors/node-sass/
phantomjs_cdnurl=http://npm.taobao.org/mirrors/phantomjs
ELECTRON_MIRROR=http://npm.taobao.org/mirrors/electron/

woo woo woo.cn blog on.com/Chen Weixuan… blog.CSDN.net/Белый дракон1/AR…

разное

硬盘存储结构
邮箱用户目录结构

Недостатки проекта

Проект, чтобы сделать немного грубые, несовершенные некоторые функции. Например, черновики, на правой стороне при написании сообщений быстро выберите получателей, WebView не может быть очень адаптивным и так далее. Не много функций, таких как краткий ответ E-mail.

Суммировать

В этом проекте дело несложное, главным образом потому, что часть разбора электронной почты относительно сложна. Я не обращался к официальной документации, поэтому она может быть ошибочной.

Сопоставление строк использует множество регулярных выражений, и регулярные выражения, которые я написал, не очень хороши.

Для структуры проекта vue такие знания, как vuex, не в центре внимания, поэтому я взял все это одним махом.

Выше приведено резюме проекта. Если есть какие-либо ошибки, пожалуйста, поправьте меня.

Ссылаться на:MIME --- составной тип

Различные формы, кодирующие контент-кодирование