Программирование на языке Ruby.

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".

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, 'fromthisguy@wherever.com',

  ['destination@elsewhere.com']).

End.