Чтение онлайн

ЖАНРЫ

Программирование на языке Ruby
Шрифт:

imap.examine("INBOX")

total = imap.responses["EXISTS"].last # Всего сообщений.

recent = imap.responses["RECENT"].last # Непрочитанных сообщений.

imap.close # Закрыть почтовый ящик.

Отметим, что метод

examine
позволяет только читать содержимое почтового ящика. Если нужно удалить сообщения или произвести какие-то другие изменения, пользуйтесь методом
select
.

Почтовые ящики в протоколе IMAP организованы иерархически, как имена путей в UNIX. Для манипулирования почтовыми ящиками предусмотрены методы

create
,
delete
и
rename
:

imap.create("lists")

imap.create("lists/ruby")

imap.create("lists/rails")

imap.create("lists/foobar")

# Уничтожить последний созданный ящик:

imap.delete("lists/foobar")

Имеются также методы

list
(получить список всех почтовых ящиков) и
lsub
(получить список «активных» ящиков, на которые вы «подписались»). Метод
status
возвращает информацию о состоянии ящика.

Метод

search
находит сообщения, удовлетворяющие заданному критерию, а метод
fetch
возвращает запрошенное сообщение:

msgs = imap.search("ТО","lupin")

msgs.each do |mid|

 env = imap.fetch(mid, "ENVELOPE")[0].attr["ENVELOPE"]

 puts "От #{env.from[0].name} #{env.subject}"

end

Команда

fetch
в предыдущем примере выглядит так сложно, потому что возвращает массив хэшей. Сам конверт тоже представляет собой сложную структуру; некоторые методы доступа к нему возвращают составные объекты, другие — просто строки.

В протоколе IMAP есть понятия UID (уникального идентификатора) и порядкового номера сообщения. Обычно методы типа

fetch
обращаются к сообщениям по номерам, но есть и варианты (например,
uid_fetch
) для обращения по UID. У нас нет места объяснять, почему нужны обе системы идентификации, но если вы собираетесь серьезно работать с IMAP, то должны понимать различие между ними (и никогда не путать одну с другой).

Библиотека

net/imap
располагает разнообразными средствами для работы с почтовыми ящиками, сообщениями, вложениями и т.д. Дополнительную информацию поищите в онлайновой документации на сайте ruby-doc.org.

18.2.6. Кодирование и декодирование вложений

Для вложения в почтовое сообщение или в сообщение, отправляемое в конференцию, файл обычно кодируется. Как правило, применяется кодировка

base64
, для работы с которой служит метод
pack
с аргументом
m
:

bin = File.read("new.gif")

str = [bin].pack("m") # str закодирована.

orig = str.unpack("m")[0] # orig == bin

Старые почтовые клиенты работали с кодировкой uuencode/uudecode. В этом случае вложение просто добавляется в конец текста сообщения и ограничивается строками

begin
и
end
, причем в строке
begin
указываются также разрешения на доступ к файлу (которые можно и проигнорировать) и имя файла.
Аргумент u метода
pack
позволяет представить строку в кодировке
uuencode
. Пример:

# Предположим, что mailtext содержит текст сообщения.

filename = "new.gif"

bin = File.read(filename)

encoded = [bin].pack("u")

mailtext << "begin 644 #{filename}"

mailtext << encoded

mailtext << "end"

# ...

На принимающей стороне мы должны извлечь закодированную информацию и декодировать ее методом

unpack
:

# ...

# Предположим, что 'attached' содержит закодированные данные

# (включая строки begin и end).

lines = attached.split("\n")

filename = /begin \d\d\d (.*)/.scan(lines[0]).first.first

encoded = lines[1..-2].join("\n")

decoded = encoded.unpack("u") # Все готово к записи в файл.

Современные почтовые клиенты работают с почтой в формате MIME; даже текстовая часть сообщения обернута в конверт (хотя клиент удаляет все заголовки, прежде чем показать сообщение пользователю).

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

base64
:

require 'net/smtp'

def text_plus_attachment(subject, body, filename)

 marker = "MIME_boundary"

 middle = "--#{marker}\n"

 ending = "--#{middle}--\n"

 content = "Content-Type: Multipart/Related; " +

"boundary=#{marker}; " +

"typw=text/plain"

 head1 = <<-EOF

MIME-Version: 1.0

#{content}

Subject: #{subject}

 EOF

 binary = File.read(filename)

 encoded = [binary].pack("m") # base64

 head2 = <<EOF

Content-Description: "#{filename}"

Content-Type: image/gif; name="#{filename}"

Content-Transfer-Encoding: Base64

Content-Disposition: attachment; filename="#{filename}"

 EOF

 # Возвращаем...

 head1 + middle + body + middle + head2 + encoded + ending

end

domain = "someserver.com"

Поделиться с друзьями: