diff --git a/apprise/attachment/base.py b/apprise/attachment/base.py
index 6ae9d3aa..11b7f8c4 100644
--- a/apprise/attachment/base.py
+++ b/apprise/attachment/base.py
@@ -29,6 +29,8 @@
 import os
 import time
 import mimetypes
+import base64
+from .. import exception
 from ..url import URLBase
 from ..utils import parse_bool
 from ..common import ContentLocation
@@ -289,6 +291,37 @@ class AttachBase(URLBase):
 
         return False if not retrieve_if_missing else self.download()
 
+    def base64(self, encoding='utf-8'):
+        """
+        Returns the attachment object as a base64 string otherwise
+        None is returned if an error occurs.
+
+        If encoding is set to None, then it is not encoded when returned
+        """
+        if not self:
+            # We could not access the attachment
+            self.logger.error(
+                'Could not access attachment {}.'.format(
+                    self.url(privacy=True)))
+            raise exception.AppriseFileNotFound("Attachment Missing")
+
+        try:
+            with open(self.path, 'rb') as f:
+                # Prepare our Attachment in Base64
+                return base64.b64encode(f.read()).decode(encoding) \
+                    if encoding else base64.b64encode(f.read())
+
+        except (TypeError, FileNotFoundError):
+            # We no longer have a path to open
+            raise exception.AppriseFileNotFound("Attachment Missing")
+
+        except (TypeError, OSError, IOError) as e:
+            self.logger.warning(
+                'An I/O error occurred while reading {}.'.format(
+                    self.name if self else 'attachment'))
+            self.logger.debug('I/O Exception: %s' % str(e))
+            raise exception.AppriseDiskIOError("Attachment Access Error")
+
     def invalidate(self):
         """
         Release any temporary data that may be open by child classes.
diff --git a/apprise/plugins/sendgrid.py b/apprise/plugins/sendgrid.py
index 56a99a57..627815c7 100644
--- a/apprise/plugins/sendgrid.py
+++ b/apprise/plugins/sendgrid.py
@@ -50,6 +50,7 @@ import requests
 from json import dumps
 
 from .base import NotifyBase
+from .. import exception
 from ..common import NotifyFormat
 from ..common import NotifyType
 from ..utils import parse_list
@@ -57,6 +58,7 @@ from ..utils import is_email
 from ..utils import validate_regex
 from ..locale import gettext_lazy as _
 
+
 # Extend HTTP Error Messages
 SENDGRID_HTTP_ERROR_MAP = {
     401: 'Unauthorized - You do not have authorization to make the request.',
@@ -90,6 +92,9 @@ class NotifySendGrid(NotifyBase):
     # The default Email API URL to use
     notify_url = 'https://api.sendgrid.com/v3/mail/send'
 
+    # Support attachments
+    attachment_support = True
+
     # Allow 300 requests per minute.
     # 60/300 = 0.2
     request_rate_per_sec = 0.2
@@ -297,7 +302,8 @@ class NotifySendGrid(NotifyBase):
         """
         return len(self.targets)
 
-    def send(self, body, title='', notify_type=NotifyType.INFO, **kwargs):
+    def send(self, body, title='', notify_type=NotifyType.INFO, attach=None,
+             **kwargs):
         """
         Perform SendGrid Notification
         """
@@ -331,6 +337,36 @@ class NotifySendGrid(NotifyBase):
             }],
         }
 
+        if attach and self.attachment_support:
+            attachments = []
+
+            # Send our attachments
+            for no, attachment in enumerate(attach, start=1):
+                try:
+                    attachments.append({
+                        "content": attachment.base64(),
+                        "filename": attachment.name
+                        if attachment.name else f'attach{no:03}.dat',
+                        "type": "application/octet-stream",
+                        "disposition": "attachment"
+                    })
+
+                except exception.AppriseException:
+                    # We could not access the attachment
+                    self.logger.error(
+                        'Could not access attachment {}.'.format(
+                            attachment.url(privacy=True)))
+                    return False
+
+                self.logger.debug(
+                    'Appending SendGrid attachment {}'.format(
+                        attachment.url(privacy=True)))
+
+            # Append our attachments to the payload
+            _payload.update({
+                'attachments': attachments,
+            })
+
         if self.template:
             _payload['template_id'] = self.template
 
diff --git a/test/test_attach_file.py b/test/test_attach_file.py
index d0734832..8c369784 100644
--- a/test/test_attach_file.py
+++ b/test/test_attach_file.py
@@ -29,6 +29,7 @@
 import re
 import time
 import urllib
+import pytest
 from unittest import mock
 
 from os.path import dirname
@@ -37,6 +38,7 @@ from apprise.attachment.base import AttachBase
 from apprise.attachment.file import AttachFile
 from apprise import AppriseAttachment
 from apprise.common import ContentLocation
+from apprise import exception
 
 # Disable logging for a cleaner testing output
 import logging
@@ -210,3 +212,37 @@ def test_attach_file():
     # Test hosted configuration and that we can't add a valid file
     aa = AppriseAttachment(location=ContentLocation.HOSTED)
     assert aa.add(path) is False
+
+
+def test_attach_file_base64():
+    """
+    API: AttachFile() with base64 encoding
+
+    """
+
+    # Simple gif test
+    path = join(TEST_VAR_DIR, 'apprise-test.gif')
+    response = AppriseAttachment.instantiate(path)
+    assert isinstance(response, AttachFile)
+    assert response.name == 'apprise-test.gif'
+    assert response.mimetype == 'image/gif'
+
+    # now test our base64 output
+    assert isinstance(response.base64(), str)
+    # No encoding if we choose
+    assert isinstance(response.base64(encoding=None), bytes)
+
+    # Error cases:
+    with mock.patch('os.path.isfile', return_value=False):
+        with pytest.raises(exception.AppriseFileNotFound):
+            response.base64()
+
+    with mock.patch("builtins.open", new_callable=mock.mock_open,
+                    read_data="mocked file content") as mock_file:
+        mock_file.side_effect = FileNotFoundError
+        with pytest.raises(exception.AppriseFileNotFound):
+            response.base64()
+
+        mock_file.side_effect = OSError
+        with pytest.raises(exception.AppriseDiskIOError):
+            response.base64()
diff --git a/test/test_plugin_sendgrid.py b/test/test_plugin_sendgrid.py
index 328e8a00..4c775ca0 100644
--- a/test/test_plugin_sendgrid.py
+++ b/test/test_plugin_sendgrid.py
@@ -28,9 +28,13 @@
 
 from unittest import mock
 
+import os
 import pytest
 import requests
 
+from apprise import Apprise
+from apprise import NotifyType
+from apprise import AppriseAttachment
 from apprise.plugins.sendgrid import NotifySendGrid
 from helpers import AppriseURLTester
 
@@ -38,6 +42,9 @@ from helpers import AppriseURLTester
 import logging
 logging.disable(logging.CRITICAL)
 
+# Attachment Directory
+TEST_VAR_DIR = os.path.join(os.path.dirname(__file__), 'var')
+
 # a test UUID we can use
 UUID4 = '8b799edf-6f98-4d3a-9be7-2862fb4e5752'
 
@@ -161,3 +168,36 @@ def test_plugin_sendgrid_edge_cases(mock_post, mock_get):
         from_email='l2g@example.com',
         bcc=('abc@def.com', '!invalid'),
         cc=('abc@test.org', '!invalid')), NotifySendGrid)
+
+
+@mock.patch('requests.get')
+@mock.patch('requests.post')
+def test_plugin_sendgrid_attachments(mock_post, mock_get):
+    """
+    NotifySendGrid() Attachments
+
+    """
+
+    request = mock.Mock()
+    request.status_code = requests.codes.ok
+
+    # Prepare Mock
+    mock_post.return_value = request
+    mock_get.return_value = request
+
+    path = os.path.join(TEST_VAR_DIR, 'apprise-test.gif')
+    attach = AppriseAttachment(path)
+    obj = Apprise.instantiate('sendgrid://abcd:user@example.com')
+    assert isinstance(obj, NotifySendGrid)
+    assert obj.notify(
+        body='body', title='title', notify_type=NotifyType.INFO,
+        attach=attach) is True
+
+    mock_post.reset_mock()
+    mock_get.reset_mock()
+
+    # Try again in a use case where we can't access the file
+    with mock.patch("builtins.open", side_effect=OSError):
+        assert obj.notify(
+            body='body', title='title', notify_type=NotifyType.INFO,
+            attach=attach) is False