
Security News
Astral Launches pyx: A Python-Native Package Registry
Astral unveils pyx, a Python-native package registry in beta, designed to speed installs, enhance security, and integrate deeply with uv.
== Multipurpose Internet Mail Extensions (MIME)
A library for building RFC compliant Multipurpose Internet Mail Extensions (MIME) messages. It can be used to construct standardized MIME messages for use in client/server communications, such as Internet mail or HTTP multipart/form-data transactions.
== See Also
== Media Inheritance Heirarchy
Media* ^ | |--DiscreteMedia* | ^ | | | |--Application | |--Audio | |--Image | |--Text | +--Video | +--CompositeMedia* ^ | |--Message** | ^ | | | |--ExternalBody** | |--Partial** | +--RFC822** | +--Multipart* ^ | |--Alternative |--Digest** |--Encrypted** |--FormData |--Mixed |--Parallel** |--Related |--Report** +--Signed**
* Abstract Class
** Not implemented
== MIME Message Format
________________ -------------------+
| | | | RFC822 & MIME | | | Headers | | || | ________________ | | | | | MIME Headers | | |~~~~~~~~~~~~~~~~| <-- MIME Entity* |--- RFC822/MIME | Body* | (N) | Message || | ________________ | | | | | MIME Headers | | |~~~~~~~~~~~~~~~~| <-- MIME Entity* | | Body* | (N+1) | |________________| | -------------------+
* Optional
Each MIME Entity must be a discrete (MIME::DiscreteMedia) or composite (MIME::CompositeMedia) media type. Because MIME is recursive, composite entity bodies may contain other composite or discrete entities and so on. However, discrete entities are non-recursive and contain only non-MIME bodies.
== Examples
First things first!
require 'mime' include MIME # allow ommision of "MIME::" namespace in examples below
=== Instantiate a DiscreteMedia object
Discrete media objects, such as text or video, can be created directly using a specific discrete media class or indirectly via the factory. If the media is file backed, like the example below, the factory will open and read the data file and determine the MIME type for you.
file = '/tmp/data.xml'
text_media = Text.new(File.read(file), 'xml') # media class text_media = DiscreteMediaFactory.create(file) # media factory
Discrete media objects can then be embedded in MIME messages as we will see in the next example.
=== Simple text/plain RFC822 email message
Create a well-formed email message with multiple recipients. The string representation of the message (i.e. to_s) can then be sent directly via an SMTP client.
msg = Mail.new # blank message with current date and message ID headers msg.date -= 3600 # change date to 1 hour ago msg.subject = 'This is important' # add subject msg.headers.set('Priority', 'urgent') # add custom header
msg.body = Text.new('hello, world!', 'plain', 'charset' => 'us-ascii')
msg.from = {'boss@example.com' => 'Boss Man'} # mailbox hash msg.bcc = 'boss+home@example.com' # mailbox string msg.cc = %w(secretary@example.com manager@example.com) # mailbox array msg.to = { 'list@example.com' => nil, # no name display 'john@example.com' => 'John Doe', 'jane@example.com' => 'Jane Doe', }
msg.to_s # ready to be sent via SMTP
=== RFC822 email message with image body
Embedding a single image within an email message requires a single discrete media image. However, embedding multiple images requires a multipart/mixed composite media type to encapsulate all of the discrete media images.
==== Email body with single image
img = Image.new(File.read('screenshot.png'), 'png') img.disposition = 'inline' img.description = 'My screenshot' email = Mail.new(img)
==== Email body with multiple images
msg = Multipart::Mixed.new msg.inline Image.new(File.read('screenshot1.png'), 'png') msg.inline Image.new(File.read('screenshot2.png'), 'png') msg.description = 'My screenshots' email = Mail.new(msg)
=== Plain text multipart/mixed message with a file attachment
The multipart/mixed content type can be used to aggregate multiple unrelated entities, such as text and an image.
text = DiscreteMediaFactory.create('/tmp/data.txt') image = DiscreteMediaFactory.create('/tmp/ruby.png')
mixed_msg = Multipart::Mixed.new mixed_msg.add(text) mixed_msg.attach(image) mixed_msg.to_s
=== Plain text and HTML multipart/alternative MIME message
The multipart/alternative content type allows for multiple, alternatively formatted versions of the same content, such as plain text and HTML. Clients are then responsible for choosing the most suitable version for display.
text_msg = Text.new(<<TEXT_DATA, 'plain') Hello, world!
Ruby is cool! TEXT_DATA
html_msg = Text.new(<<HTML_DATA, 'html')
Ruby is cool!
HTML_DATAmsg = Multipart::Alternative.new msg.add(text_msg) # add the simplest representations first msg.add(html_msg) msg.to_s # or send in an email: Mail.new(msg)
=== HTML multipart/related MIME email with embedded image
Sometimes it is desirable to send a document that is made up of many separate parts. For example, an HTML page with embedded images. The multipart/related content type aggregates all the parts and creates the means for the root entity to reference the other entities.
Notice the src of the img tag.
image = DiscreteMediaFactory.create('/tmp/ruby.png') image.transfer_encoding = 'binary' # could base64 encode the image instead
html_msg = Text.new(<<EOF, 'html', 'charset' => 'utf-8')
related_msg = Multipart::Related.new related_msg.add(html_msg) # first entity added becomes the root object related_msg.inline(image) # the root object references the inline image
email_msg = Mail.new(related_msg) email_msg.to = 'jane@example.com' email_msg.from = 'john@example.com' email_msg.subject = 'Ruby is cool, checkout the picture' email_msg.to_s # ready to send HTML email with image
=== HTML form with file upload using multipart/form-data encoding
This example builds a representation of an HTML form that can be POSTed to an HTTP server. It contains a single text input and a file input.
name_field = Text.new('Joe Blow') portrait_path = '/tmp/joe_portrait.jpg' portrait_field = Image.new(File.read(portrait_path), 'jpeg') portrait_field.transfer_encoding = 'binary'
form_data = Multipart::FormData.new form_data.add(name_field, # field value 'name') # field name, i.e. HTML input type=text form_data.add(portrait_field, # field value 'portrait', # field name, i.e. HTML input type=file portrait_path) # suggest image filename to server form_data.to_s # ready to POST via HTTP
=== HTML form with file upload via DiscreteMediaFactory
The outcome of this example is identical to the previous one. The only semantic difference is that the DiscreteMediaFactory module is used to instantiate the image object and automatically set the content type and FormData filename.
name_field = Text.new('Joe Blow') portrait_path = '/tmp/joe_portrait.jpg' portrait_field = DiscreteMediaFactory.create(portrait_path) portrait_field.transfer_encoding = 'binary'
form_data = Multipart::FormData.new form_data.add(name_field, 'name') form_data.add(portrait_field, 'portrait') form_data.to_s
=== Avoid "embarrassing line wraps" using flowed format for text/plain
Text/Plain is usually displayed as preformatted text, often in a fixed font. That is, the characters start at the left margin of the display window, and advance to the right until a CRLF sequence is seen, at which point a new line is started, again at the left margin. When a line length exceeds the display window, some clients will wrap the line, while others invoke a horizontal scroll bar. The result: embarrassing line wraps.
Flowed format allows the sender to express to the receiver which lines can be considered a logical paragraph, and thus flowed (wrapped and joined) as appropriate.
long_paragraph = "This is a continuous fixed-line-length paragraph that is longer than " + "80 characters and will be soft line wrapped after the word '80'.\n\n"
flowed_txt = ContentFormats::TextFlowed.encode(long_paragraph * 2) flowed_msg = Text.new(flowed_txt, 'plain', 'format' => 'flowed') flowed_msg.to_s # neatly formatted text compatible with small to large screens
== More Examples
For many more examples, check the test class MIMETest.
== Links
Homepage :: https://ecentryx.com/gems/mime Ruby Gem :: https://rubygems.org/gems/mime Source Code :: https://bitbucket.org/pachl/mime/src Bug Tracker :: https://bitbucket.org/pachl/mime/issues Validators :: Please check all of your messages using the following lint tools and report errors to the bug tracker or directly to pachl@ecentryx.com with "Ruby MIME" in the subject.
- http://www.apps.ietf.org/content/message-lint
- https://tools.ietf.org/tools/msglint/
== History
== License
({ISC License}[http://opensource.org/licenses/ISC])
Copyright (c) 2017, Clint Pachl pachl@ecentryx.com
Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
FAQs
Unknown package
We found that mime demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
Astral unveils pyx, a Python-native package registry in beta, designed to speed installs, enhance security, and integrate deeply with uv.
Security News
The Latio podcast explores how static and runtime reachability help teams prioritize exploitable vulnerabilities and streamline AppSec workflows.
Security News
The latest Opengrep releases add Apex scanning, precision rule tuning, and performance gains for open source static code analysis.