A lightweight, modular Ruby wrapper for the Microsoft Graph API.
Designed for developers who need a simple, robust way to send emails (and eventually handle Teams/OneDrive) without the overhead of the massive official SDK.
- π Lightweight: Zero bloat. Only what you need.
- β‘ High Performance: Built-in Token Caching. It reuses OAuth tokens until they expire, preventing rate-limiting and reducing latency.
- π§ Advanced Email: Supports HTML bodies and Inline Images (CIDs) out of the box.
- π‘οΈ Robust Error Handling: Maps complex Microsoft JSON errors to standard Ruby exceptions (e.g.,
RateLimitErrorwith retry headers). - π Modular: Architecture designed to easily extend to Teams, Calendar, and Drive in the future.
Add this line to your application's Gemfile:
gem 'ms_graph_lite'And then execute:
$ bundle install
Before using this gem, you need credentials from the Microsoft Azure Portal:
- Create a new App Registration.
- Go to API Permissions and add
Mail.Send(Application Permission). - Grant Admin Consent for the permission.
- Generate a Client Secret.
Configure the gem in an initializer (e.g., config/initializers/ms_graph_lite.rb for Rails):
MsGraphLite.configure do |config|
config.tenant_id = ENV['AZURE_TENANT_ID']
config.client_id = ENV['AZURE_CLIENT_ID']
config.client_secret = ENV['AZURE_CLIENT_SECRET']
endmailer = MsGraphLite::Resources::Mail.new
mailer.send(
from_email: 'notifications@yourcompany.com',
to_recipients: ['user@example.com', 'admin@example.com'],
subject: 'Welcome to the Platform',
content: '<h1>Hello!</h1><p>Welcome aboard.</p>'
)To send regular files (PDFs, CSVs, etc.):
attachments = [
{ path: '/tmp/report.pdf' },
{ path: '/tmp/invoice.csv' }
]
mailer.send(
from_email: 'bot@yourcompany.com',
to_recipients: 'finance@example.com',
subject: 'Weekly Report',
content: 'Please find the attached report.',
attachments: attachments
)To embed an image inside the email body (like a logo or banner), you must provide a cid (Content ID) in the attachment hash and reference it in your HTML using src="cid:...".
# 1. Prepare the HTML with a CID reference
html_body = <<~HTML
<h2>Weekly Update</h2>
<p>Here is our performance chart:</p>
<img src="cid:performance_chart" alt="Chart" width="500">
<p>Regards, Team.</p>
HTML
# 2. Attach the image with the matching CID
attachments = [
{
path: './assets/chart.png',
cid: 'performance_chart' # Matches the src above
}
]
# 3. Send
mailer.send(
from_email: 'bot@yourcompany.com',
to_recipients: 'manager@example.com',
subject: 'Performance Update',
content: html_body,
attachments: attachments
)The most efficient way to check for new emails periodically (e.g., every 5 minutes). It only returns what changed.
# 1. Load the last "Delta Link" from your DB/File (nil if first run)
# You need to implement the MyDB class to read the link from a text file or database.
# Checkout the examples/read_emails.rb for a working example with Ruby pstore.
last_link = MyDb.get_link
# 2. Call Delta
response = mailer.delta(user_email: "support@yourcompany.com", delta_link: last_link)
# 3. Process Changes
response['value'].each do |msg|
if msg['@removed']
puts "ποΈ Email Deleted: #{msg['id']}"
else
puts "π© New/Updated: #{msg['subject']}"
end
end
# 4. Save the new link for next time
new_link = response['@odata.deltaLink'] || response['@odata.nextLink']
MyDb.save_link(new_link)When iterating through emails, use these keys to access data:
| Field | Accessor |
|---|---|
| Subject | email['subject'] |
| Body (HTML) | email['body']['content'] |
| Preview Text | email['bodyPreview'] |
| Sender Email | email['from']['emailAddress']['address'] |
| Sender Name | email['from']['emailAddress']['name'] |
| Recipients (To) | email['toRecipients'] (Array) |
| Has Attachments? | email['hasAttachments'] (Boolean) |
| Is Read? | email['isRead'] (Boolean) |
| Message ID | email['id'] |
| Received Time | email['receivedDateTime'] |
Stop guessing why your API calls failed. MsGraphLite maps Microsoft errors to specific Ruby exceptions.
begin
mailer.send(...)
rescue MsGraphLite::RateLimitError => e
# Microsoft is throttling us. The exception knows when we can retry.
puts "Too many requests! Sleeping for #{e.retry_after} seconds."
sleep(e.retry_after)
retry
rescue MsGraphLite::AuthenticationError
# Your Client Secret likely expired or Tenant ID is wrong.
AdminNotifier.alert("Azure Auth Failed!")
rescue MsGraphLite::ResourceNotFoundError
# The 'from_email' user might not exist in your Azure Tenant.
puts "The sender email address does not exist."
rescue MsGraphLite::Error => e
# Handle generic API errors
puts "Graph API Error: #{e.message} (Code: #{e.code})"
endAfter checking out the repo, run bin/setup to install dependencies.
We use RSpec and WebMock to test without hitting real Microsoft servers.
bundle exec rspec
Bug reports and pull requests are welcome on GitHub. This project is intended to be a safe, welcoming space for collaboration.
- Fork it
- Create your feature branch (
git checkout -b my-new-feature) - Commit your changes (
git commit -am 'Add some feature') - Push to the branch (
git push origin my-new-feature) - Create a new Pull Request
The gem is available as open source under the terms of the MIT License.