О проекте
Это мой дипломный проект (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
- текст, в основном text/html и text/plain, содержимое необходимо декодировать с помощью Content-Transfer-Encoding, распространенными кодировками передачи являются base64 и кавычки-печать
- многочастный, делится на смешанный, альтернативный и родственный. multipart имеет граничный разделитель, который делит тело сообщения на разные сегменты.
- смешанный тип с вложениями
- альтернатива - это тип, в котором существует как обычный текст, так и гипертекст.
- связанный - это встроенный тип ресурса, например, содержимое в формате html, но в html есть изображения, извлеките изображения и отправьте их в виде вложений.
- Изображение, приложение, обычно формат, который появляется в приложении
второй шаг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--
анализировать:
- Тип содержимого
multipart/mixed
, указывая, что тип вложения включен - Родительский сегмент появляется в конце, и разделенный массив может занять первый элемент.
- Согласно сегментации подсегментации, сегмент имеет свою собственную границу, тип контента и Charset.
- Первый абзац представляет собой альтернативное небольшое электронное письмо, содержащее как обычный текст, так и гипертекст. Затем разделите его по границе
- После синтаксического анализа текстовое содержимое
12\r\n3
- После синтаксического анализа гипертекстовое содержимое может быть
<div>12</div><div>3</div>
- После синтаксического анализа текстовое содержимое
- Второй абзац — вложение типа приложения, судя по кодировке и разбору кодировки имя файла
邮件详情.png
- Первый абзац представляет собой альтернативное небольшое электронное письмо, содержащее как обычный текст, так и гипертекст. Затем разделите его по границе
Вопросы, о которых следует помнить при написании
- Обнаружен Content-type как
multipart/related;type="multipart/alternative";boundary="----=_NextPart_5A6951CD_6F185580_3879981A
, это надо считать родственным, а не альтернативным, по комплексному - Обратите внимание, что правила синтаксического анализа связанных типов и смешанных типов одинаковы.
- Некоторые электронные письма имеют неполные значения (например, отсутствие кодировки), и вам необходимо установить значения по умолчанию.
- Ошибка синтаксического анализа значения base64 связана с тем, что base64 имеет новую строку и ее необходимо удалить.
Хранилище электронной почты
── attr #有邮件uid等简单信息
── body
├──attachment #附件
├──bodyHtml #超文本
├──bodyText #纯文本
── emailText #完整的邮件文本
── header #头部信息
Content-type
Преобразование повторно сохраняется, в противном случае, если вы хотите судить о разных типах различной обработки во время отображения. Очевидно, хранить предобработку лучше
- Если тип HTML, BodyHTML отдельно сохраняет файл, а значение bodyhtml - это путь к файлу. Здесь вам нужно рассмотреть HTML не является полной страницей, а фрагмент.
- Если это смешанный тип, сохраните вложение в отдельном файле, а также сохраните его как путь к файлу.
- Что касается альтернативных и родственных, здесь нет необходимости рассматривать их отдельно. Поскольку альтернативой является сосуществование обычного текста и гипертекста, то есть повторение, гипертекст — это фрагмент html, включая формат, а обычный текст содержит только текст, просто сохраните гипертекст; связанный — это то же самое, что и правило смешанного синтаксического анализа, и ему необходимо указывать ресурсы Синтезируйте полный html и сохраните html отдельно.
if (contentType.match(htmlTypeReg)) {...} //单独存储html
else if (contentType.match(mixedMultipart)) {...} // 单独存储附件
if (!contentType.match(htmlTypeReg)) {...} //非htmlTypeReg也进行单独存储html
показать почту
Хранилище очень регулярное, поэтому логика очень понятна при отображении.
- bodyHtml начинается с
.html
В конце это HTML-путь, который импортируется с SRC веб-просмотра - bodyHtml не является путем, вставьте html-фрагмент
- Без bodyHtml вставьте bodyText
- Если есть вложение, оно будет отображаться, а если вложения нет, оно отображаться не будет.
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 --- составной тип