#lua #smtp #luasocket
#lua #smtp #luasocket
Вопрос:
Я пишу скрипт, который может отправлять электронные письма с помощью LuaSocket SMTP. Теперь я хотел бы, чтобы мой скрипт также мог читать мои электронные письма.
У меня есть учетная запись электронной почты в службе, которая поддерживает IMAP.
IMAP host and port: example.com:143
My E-Mail: doesnotexist@example.com
The password: notsaying
Как я могу заставить свой скрипт получать электронную почту из этой службы, чтобы я мог отображать ее содержимое?
Редактировать:
Я пробовал imap4 с https://github.com/vrld/imap4.lua но, похоже, это еще не конец.
Я попробовал этот пример:
require 'luarocks.require'
local imap4 = require 'imap4'
local username = "doesnotexist@example.com"
local password = "notsaying"
local connection = imap4('example.com', 143)
print(table.concat(connection:capability(), ', '))
assert(connection:isCapable('IMAP4rev1'))
connection:login(username, password)
for mb, info in pairs(connection:lsub()) do
local stat = connection:status(mb, {'MESSAGES', 'RECENT', 'UNSEEN'})
print(mb, stat.MESSAGES, stat.RECENT, stat.UNSEEN)
end
local info = connection:examine('INBOX')
print(info.exist, info.recent)
for _,v in pairs(connection:fetch('UID BODY.PEEK[HEADER.FIELDS (From Date Subject)]', (info.exist-3)..':*')) do
print(v.id, v.UID, v.BODY.value)
end
connection:logout()
Я только добавил имя пользователя и пароль и изменил сервер и порт из исходного примера и изменил самую последнюю выборку с 4 на 3. Я также удалил комментарии, так как их много. Кроме тех, которые я больше ничего не изменял, это в основном тот же пример.
Кажется, что он правильно входит в систему, используя мои учетные данные и правильный сервер и порт, но у него есть какая-то проблема, которую я не могу отладить.
Приведенный выше пример выводит:
IMAP4rev1, CHILDREN, NAMESPACE
INBOX.Sent 3 0 0
INBOX 4 0 0
4 0
lua: example.lua:24: attempt to index field 'BODY' (a nil value)
stack traceback:
example.lua:24: in main chunk
[C]: ?
Это показывает, что у меня есть 4 электронных письма в моем почтовом ящике и 3 в моем отправленном, что правильно.
Комментарии:
1. Вы пробовали что-нибудь? Вы читали документацию? Вы пробовали какой-то код и потерпели неудачу?
2. Я обновил свой вопрос.
3. В комментарии в исходном примере упоминается «Информация о списке 4 самых последних писем», когда он ссылается на
(info.exist-4)..':*'
. Поскольку в вашем почтовом ящике всего четыре письма, возможно, вам следует использовать меньшее число, чем 4…4. Вы правы, обновили мой вопрос. Я изменил -4 на -3. Теперь возникла новая проблема, он не находит поле «ТЕЛО». Я проверил, что все 4 сообщения электронной почты имеют тело.
5. может быть, вы можете использовать только pop3 дополнительно с tls ( github.com/moteus/lua-pop3 )? Я использую эту библиотеку в службе, которая опрашивает почтовый сервер. Также вы можете recv rfc822 через imap и проанализировать его с помощью pop3.message class . я могу опубликовать пример завтра
Ответ №1:
В этом примере используется библиотека imap4 для получения сообщения и pop3.message для анализа.
local imap4 = require "imap4"
local Message = require "pop3.message"
local connection = imap4('imap.qip.ru', 143)
assert(connection:isCapable('IMAP4rev1'))
connection:login('****', '****')
-- Select INBOX with read only permissions.
local info = connection:examine('INBOX')
print(info.exist, info.recent)
-- List info on the 4 most recent mails.
for _,v in pairs(connection:fetch('RFC822', (info.exist-4)..':*')) do
print("-------------------------")
local msg = Message(v.RFC822)
print("ID: ", msg:id())
print("subject: ", msg:subject())
print("to: ", msg:to())
print("from: ", msg:from())
print("from addr: ", msg:from_address())
print("reply: ", msg:reply_to())
print("reply addr: ", msg:reply_address())
print("trunc: ", msg:is_truncated())
for i,v in ipairs(msg:full_content()) do
if v.text then print(" ", i , "TEXT: ", v.type, #v.text)
else print(" ", i , "FILE: ", v.type, v.file_name or v.name, #v.data) end
end
end
-- close connection
connection:logout()
Комментарии:
1. Спасибо, я приму этот ответ. Я не очень разбираюсь в IMAP, этот ответ помог мне заставить его работать с (по-видимому) нестандартно совместимым сервером IMAP, или, по крайней мере, мне это кажется нестандартным. Я опубликую ответ ниже, объясняющий, почему example
Ответ №2:
Сначала попробуйте решение moeus. Мой пример беспокоит только в том случае, если сервер, который вам нужен, не поддерживает RFC822 или вообще не соответствует стандарту.
В этом ответе я кратко объясню, почему исходный пример не сработал, а также приведу пример без RFC822, поскольку сервер, с которым мне приходится работать, не понимает RFC822 и многие другие ключевые слова, которые он должен понимать в соответствии со стандартом IMAP 4
В примере мне пришлось изменить:
connection:fetch('UID BODY.PEEK[HEADER.FIELDS (From Date Subject)]', (info.exist-3)..':*'))
Для:
connection:fetch('(UID BODY.PEEK[HEADER.FIELDS (From Date Subject)])', (info.exist-3)..':*'))
Обратите внимание на круглые скобки, вот почему пример не сработал.
Ответ Moteus с RFC822 у меня не работает, потому что сервер, с которым мне приходится работать, нестандартный. Вот как я заставил это работать:
local imap4 = require "imap4"
local Message = require "pop3.message"
local connection = imap4('imap.qip.ru', 143)
assert(connection:isCapable('IMAP4rev1'))
connection:login('****', '****')
-- Select INBOX with read only permissions.
local info = connection:examine('INBOX')
print(info.exist, info.recent)
-- List info on the 4 most recent mails.
for _,v in pairs(connection:fetch('(UID BODY.PEEK[HEADER.FIELDS (Subject To From Date)])', (info.exist-4)..':*')) do
print("-------------------------")
local msg = Message(v.BODY.value)
print("ID: ", msg:id())
print("subject: ", msg:subject())
print("to: ", msg:to())
print("from: ", msg:from())
print("from addr: ", msg:from_address())
print("reply: ", msg:reply_to())
print("reply addr: ", msg:reply_address())
print("trunc: ", msg:is_truncated())
for i,v in ipairs(msg:full_content()) do
if v.text then print(" ", i , "TEXT: ", v.type, #v.text)
else print(" ", i , "FILE: ", v.type, v.file_name or v.name, #v.data) end
end
end
-- close connection
connection:logout()
В отличие от примера Moteus, вам придется извлекать текст отдельно.
Вы можете получить текст письма следующим образом:
connection:fetch('(BODY.PEEK[TEXT])', id)