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('
')
filename = /begin ddd (.*)/.scan(lines[0]).first.first
encoded = lines[1..-2].join('
')
decoded = encoded.unpack('u') # Все готово к записи в файл.
Современные почтовые клиенты работают с почтой в формате MIME; даже текстовая часть сообщения обернута в конверт (хотя клиент удаляет все заголовки, прежде чем показать сообщение пользователю).
Подробное рассмотрение формата MIME заняло бы слишком много места, да и не относится к рассматриваемой теме. Но в следующем простом примере показано, как можно закодировать и отправить сообщение, содержащее текстовую часть и двоичное вложение. Двоичные куски обычно представлены в кодировке base64
:
require 'net/smtp'
def text_plus_attachment(subject, body, filename)
marker = 'MIME_boundary'
middle = '--#{marker}
'
ending = '--#{middle}--
'
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'
smtp = 'smtp.#{domain}'
user, pass = 'elgar','enigma'
body = <<EOF
Это мое сообщение. Особо
говорить не о чем. Я вложил
небольшой GIF-файл.
-- Боб
EOF
mailtext = text_plus_attachment('Привет...',body,'new.gif')
Net::SMTP.start(smtp, 25, domain, user, pass, :plain) do |mailer|
mailer.sendmail(mailtext, '[email protected]',
['[email protected]'])
end
18.2.7. Пример: шлюз между почтой и конференциями
В онлайновых сообществах общение происходит разными способами. К наиболее распространенным относятся списки рассылки и конференции (новостные группы).
Но не каждый хочет подписываться на список рассылки и ежедневно получать десятки сообщений; кто-то предпочитает время от времени заходить в конференцию и просматривать новые сообщения. С другой стороны, есть люди, которым система Usenet кажется слишком медлительной — они хотели бы видеть сообщение, пока еще электроны не успели остыть.