Skip to main content

S3 Bucket

LoopMessage keeps attachments from inbound messages for only about 1 hour. Connect an S3-compatible storage provider to keep these files in your own bucket for as long as you need. This also gives you more control over privacy because the files are automatically uploaded to storage that you manage. Supported providers include Amazon S3, DigitalOcean Spaces, Cloudflare R2, and other services that support the S3 API.

After a successful upload, LoopMessage replaces the original attachment URL with a URL for the stored file. You can use a public URL or a temporary private presigned URL.

This integration stores attachments only from inbound messages. For outbound sendings, your backend should pre-upload attachments to your storage, make URLs publicly accessible and downloadable, and send them in the POST request.

Before you begin

You will need:

  • An existing bucket or Space;
  • An access key and secret access key with permission to upload objects;
  • The bucket’s region;
  • The provider’s S3-compatible endpoint URL.

For security, create a dedicated access key for LoopMessage and limit it to the bucket and folder used for attachments. Do not use your account’s root credentials.

How to connect

Step 1: Select your organization

Sign in to Dashboard and select the organization where you want to enable attachment storage.

Step 2: Open Integrations

Open Integrations from the left sidebar and find AWS S3 Storage.

Step 3: Enter your storage settings

Click Connect and complete the following fields:

FieldWhat to enter
Access KeyThe access key ID created for your storage provider.
Secret Access KeyThe secret key paired with the access key. Keep it private.
Bucket IDThe exact name of your bucket or Space.
RegionThe bucket’s region, such as us-east-1, nyc3, or auto.
Bucket endpoint URLThe provider’s S3 API endpoint, including https://.
Make URLs public accessibleEnable this only when objects should be publicly readable. Disable it to use temporary presigned URLs.
Folder nameThe top-level folder for uploaded files. The default is loop-message.

The folder name may contain lowercase letters, numbers, and hyphens. Our service creates the required path automatically; you do not need to create the folder first.

When you submit the form, we’ll uploads a small test object to:

<folder-name>/<organization-id>/loop-message-creds-test.txt

If the test succeeds, the object is deleted and the integration is saved for the selected organization.

Configure Amazon S3

1. Create an IAM policy

Create a dedicated IAM user or access role for LoopMessage. The following policy is a starting point for a bucket where loop-message is the attachment folder. Replace YOUR_BUCKET with your bucket name.

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "LoopMessageObjectAccess",
      "Effect": "Allow",
      "Action": [
        "s3:PutObject",
        "s3:GetObject",
        "s3:DeleteObject",
        "s3:PutObjectAcl",
        "s3:AbortMultipartUpload",
        "s3:ListMultipartUploadParts"
      ],
      "Resource": "arn:aws:s3:::YOUR_BUCKET/loop-message/*"
    },
    {
      "Sid": "LoopMessageMultipartUploads",
      "Effect": "Allow",
      "Action": "s3:ListBucketMultipartUploads",
      "Resource": "arn:aws:s3:::YOUR_BUCKET"
    }
  ]
}

s3:PutObject is used to upload files. s3:GetObject is used when LoopMessage creates a presigned download URL. s3:DeleteObject is used to remove the connection-test object. The multipart permissions allow larger attachments to be uploaded reliably.

If you use a different folder name, change loop-message in the policy to that folder. You do not need to grant s3:ListBucket, s3:GetBucketLocation, or permissions to access the entire bucket.

If you keep Make URLs public accessible checkbox disabled, s3:PutObject, s3:GetObject, and s3:DeleteObject are the object permissions used by the integration. s3:PutObjectAcl is needed only because the public-URL option sends ACL: public-read. The multipart permissions are recommended because boto3 may use multipart upload for larger files.

2. Create access keys

In AWS IAM, create an access key for the dedicated user and copy the access key ID and secret access key. The secret key is shown only when it is created.

3. Enter the S3 settings in LoopMessage

Use values similar to these:

Bucket ID:           my-loopmessage-files
Region:              us-east-1
Bucket endpoint URL: https://s3.us-east-1.amazonaws.com
Folder name:         loop-message

Public accessible URLs

For private storage, leave Make URLs public accessible checkbox disabled. For public storage, enable it and configure a bucket policy that permits s3:GetObject for the attachment prefix. If your bucket uses Bucket owner enforced object ownership, ACLs are disabled; the current public-URL option may fail because it sends public-read. In that case, use private presigned URLs or update the integration to omit the ACL and rely on a bucket policy.

By default we’ll generate a seven-day presigned URL for each uploaded attachment. Grant the token object read and write permissions for the bucket; no bucket-list permission is required. The R2 S3 API endpoint is intended for API access and is not automatically a public website URL.

Configure DigitalOcean Spaces

1. Create a Space

In the DigitalOcean control panel, create a Space in the region where you want to store attachments. Note the Space name and region.

2. Create Spaces access keys

Open APISpaces Keys in DigitalOcean and create a key. Give it access only to the required Space when DigitalOcean offers that option. Copy both the key and the secret.

3. Enter the Spaces settings in Dashboard

For a Space in New York 3, the values look like this:

Bucket ID:           my-loopmessage-files
Region:              nyc3
Bucket endpoint URL: https://nyc3.digitaloceanspaces.com
Folder name:         loop-message

Replace nyc3 with your Space’s actual region, such as ams3, fra1, sgp1, or sfo3.

Public accessible URLs

If you enable public URLs, make the Space or the attachment folder publicly readable in DigitalOcean and verify that the generated object URL is accessible. Otherwise, keep public URLs disabled so we’ll returns temporary presigned URLs. The Spaces key must be allowed to write objects and, when public URLs are enabled, set the object ACL used by the integration.

Configure Cloudflare R2

1. Create an R2 bucket

In Cloudflare, open R2 Object Storage and create a bucket. Copy your Cloudflare account ID from the R2 overview or the Cloudflare dashboard URL.

2. Create an R2 API token

Create an R2 API token with permission to read and write objects in the selected bucket. Cloudflare provides an access key ID and secret access key for the token. Use those values in LoopMessage; they are not your regular Cloudflare login credentials.

3. Enter the R2 settings in Dashboard

Use the S3-compatible endpoint for your account:

Bucket ID:           my-loopmessage-files
Region:              auto
Bucket endpoint URL: https://<ACCOUNT_ID>.r2.cloudflarestorage.com
Folder name:         loop-message

Replace <ACCOUNT_ID> with your Cloudflare account ID.

Public accessible URLs

For Cloudflare R2, we recommend leaving Make URLs public accessible checkbox disabled. R2 does not support the S3 ACL: public-read option. Do not rely on object ACLs for R2: current R2 buckets use bucket-level public access instead. If this option is enabled with R2, uploads may fail because the integration sends x-amz-acl: public-read.

If you need permanent public URLs, configure public access in Cloudflare first:

  1. Open Cloudflare DashboardR2 Object Storage → select your bucket.
  2. Open the bucket’s Settings tab.
  3. Under Public access, either connect a Custom Domain or enable Public Development URL (r2.dev). Confirm the public-access prompt when Cloudflare asks you to type allow.
  4. Use the resulting public bucket URL for serving objects. A custom domain is recommended for production; r2.dev is intended for development and is rate-limited.

The current integration does not have a separate field for an R2 public/custom-domain URL and builds public URLs from the S3 API endpoint. The reliable R2 configuration is to leave Make URLs public accessible checkbox disabled.

How attachment storage works

File storage is handled for inbound messages that contain attachments:

  1. Our service downloads the attachment from its original message URL.
  2. It uploads the file to the configured bucket using the original content type when available.
  3. Files are stored using this key format: <folder-name>/<organization-id>/<file-name>.
  4. Our service updates the message so its attachment URL points to the new object.

If Make URLs public accessible checkbox is enabled, the resulting URL is a direct public URL. If it is disabled, the resulting URL is a presigned GET URL that expires after seven days. The file remains in your bucket after the URL expires and a new URL can be generated only by processing the attachment again.

The integration does not upload outbound-message attachments, and it does not delete stored attachments when a message is deleted.

Troubleshooting

The connection test fails

Check the bucket name, region, endpoint URL, and access keys. Confirm that the credentials can upload to the configured folder. The endpoint must be the provider’s S3 API endpoint, not a dashboard URL or a custom public website URL.

Files upload but public URLs do not open

The bucket or object prefix is not publicly readable, or the provider does not expose public objects through the configured endpoint. Either configure public read access correctly or disable public URLs and use presigned URLs.

Cloudflare R2 returns an access error

Make sure the R2 token includes object read and write access for the selected bucket, use auto as the region, and use the account-specific R2 endpoint. Do not use the Cloudflare dashboard URL.

Large files fail during upload

Verify that the credentials include the multipart-upload permissions listed in the AWS policy above. For S3-compatible providers, also confirm that multipart uploads are enabled for the bucket.

Security recommendations

  • Use a dedicated, least-privilege key for each organization or bucket.
  • Restrict object permissions to the attachment folder whenever possible.
  • Keep buckets private unless public access is a deliberate requirement.
  • Prefer presigned URLs for sensitive attachments.
  • Rotate the access key if it is exposed or no longer needed.