Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
6823f86
Initial commit of codeloom code
rlhagerm Apr 9, 2026
637d63a
Initial commit of codeloom code
rlhagerm Apr 9, 2026
1c18842
Merge branch 'python-sesv2-attachments' of https://github.com/rlhager…
rlhagerm Apr 14, 2026
8fd44dc
Updates to README and tools requirements.
rlhagerm Apr 14, 2026
689e773
Initial commit of codeloom code
rlhagerm Apr 9, 2026
10a6fed
Updates to README and tools requirements.
rlhagerm Apr 14, 2026
42d6dfa
Merge branch 'python-sesv2-attachments' of https://github.com/rlhager…
rlhagerm Apr 20, 2026
e4f8dc8
Updates for project structure.
rlhagerm Apr 24, 2026
23c6e69
Initial commit of codeloom code
rlhagerm Apr 9, 2026
f117f33
Updates to README and tools requirements.
rlhagerm Apr 14, 2026
0ead7b3
Updates for project structure.
rlhagerm Apr 24, 2026
d5d4297
Update to metadata order.
rlhagerm Apr 24, 2026
d55c768
Merge branch 'python-sesv2-attachments' of https://github.com/rlhager…
rlhagerm Apr 24, 2026
9f5b1ff
Update to README.
rlhagerm Apr 24, 2026
bf96ddf
Update to metadata
rlhagerm Apr 24, 2026
09dfd06
Updates to metadata.
rlhagerm Apr 24, 2026
fc286b5
Update sesv2_metadata.yaml
rlhagerm Apr 24, 2026
1806b6d
Updates to metadata.
rlhagerm Apr 24, 2026
c4167ca
Update sesv2_wrapper.py
rlhagerm Apr 24, 2026
7ad8301
Undo requirements changes.
rlhagerm Apr 24, 2026
ffea76d
Update scenario_sesv2_email_attachments.py
rlhagerm Apr 24, 2026
9793a6a
Clean up messages and hello example.
rlhagerm Apr 27, 2026
dec58c3
Adding the spec and readme.
rlhagerm Apr 27, 2026
4067378
Updates to spec and readme.
rlhagerm Apr 28, 2026
2f9701a
Metadata fixes
rlhagerm Apr 28, 2026
5aaca39
Metadata cleanup.
rlhagerm Apr 28, 2026
035a42c
Migrate Go v2 S3 examples from deprecated feature/s3/manager to featu…
brmur Apr 29, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
120 changes: 110 additions & 10 deletions .doc_gen/metadata/sesv2_metadata.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ sesv2_CreateContactList:
Python:
versions:
- sdk_version: 3
github: python/example_code/sesv2
github: python/example_code/sesv2/newsletter_scenario
excerpts:
- description:
genai: most
Expand Down Expand Up @@ -89,7 +89,7 @@ sesv2_CreateContact:
Python:
versions:
- sdk_version: 3
github: python/example_code/sesv2
github: python/example_code/sesv2/newsletter_scenario
excerpts:
- description:
genai: most
Expand All @@ -101,6 +101,15 @@ sesv2_CreateContact:
sesv2: {CreateContact}
sesv2_GetEmailIdentity:
languages:
Python:
versions:
- sdk_version: 3
github: python/example_code/sesv2/attachments_scenario
excerpts:
- description:
snippet_tags:
- python.example_code.sesv2.SESv2Wrapper.decl
- python.example_code.sesv2.GetEmailIdentityAttachment
Rust:
versions:
- sdk_version: 1
Expand Down Expand Up @@ -163,7 +172,7 @@ sesv2_ListContacts:
Python:
versions:
- sdk_version: 3
github: python/example_code/sesv2
github: python/example_code/sesv2/newsletter_scenario
excerpts:
- description:
genai: most
Expand Down Expand Up @@ -234,7 +243,14 @@ sesv2_SendEmail:
Python:
versions:
- sdk_version: 3
github: python/example_code/sesv2
github: python/example_code/sesv2/attachments_scenario
excerpts:
- description: Sends a message with optional attachments.
snippet_tags:
- python.example_code.sesv2.SESv2Wrapper.decl
- python.example_code.sesv2.SendEmailAttachment
- sdk_version: 3
github: python/example_code/sesv2/newsletter_scenario
excerpts:
- description: Sends a message to all members of the contact list.
genai: most
Expand Down Expand Up @@ -282,7 +298,14 @@ sesv2_CreateEmailIdentity:
Python:
versions:
- sdk_version: 3
github: python/example_code/sesv2
github: python/example_code/sesv2/attachments_scenario
excerpts:
- description:
snippet_tags:
- python.example_code.sesv2.SESv2Wrapper.decl
- python.example_code.sesv2.CreateEmailIdentityAttachment
- sdk_version: 3
github: python/example_code/sesv2/newsletter_scenario
excerpts:
- description:
genai: most
Expand Down Expand Up @@ -333,7 +356,14 @@ sesv2_CreateEmailTemplate:
Python:
versions:
- sdk_version: 3
github: python/example_code/sesv2
github: python/example_code/sesv2/attachments_scenario
excerpts:
- description:
snippet_tags:
- python.example_code.sesv2.SESv2Wrapper.decl
- python.example_code.sesv2.CreateEmailTemplateAttachment
- sdk_version: 3
github: python/example_code/sesv2/newsletter_scenario
excerpts:
- description:
genai: most
Expand Down Expand Up @@ -384,7 +414,7 @@ sesv2_DeleteContactList:
Python:
versions:
- sdk_version: 3
github: python/example_code/sesv2
github: python/example_code/sesv2/newsletter_scenario
excerpts:
- description:
genai: most
Expand Down Expand Up @@ -435,7 +465,14 @@ sesv2_DeleteEmailIdentity:
Python:
versions:
- sdk_version: 3
github: python/example_code/sesv2
github: python/example_code/sesv2/attachments_scenario
excerpts:
- description:
snippet_tags:
- python.example_code.sesv2.SESv2Wrapper.decl
- python.example_code.sesv2.DeleteEmailIdentityAttachment
- sdk_version: 3
github: python/example_code/sesv2/newsletter_scenario
excerpts:
- description:
genai: most
Expand Down Expand Up @@ -486,7 +523,14 @@ sesv2_DeleteEmailTemplate:
Python:
versions:
- sdk_version: 3
github: python/example_code/sesv2
github: python/example_code/sesv2/attachments_scenario
excerpts:
- description:
snippet_tags:
- python.example_code.sesv2.SESv2Wrapper.decl
- python.example_code.sesv2.DeleteEmailTemplateAttachment
- sdk_version: 3
github: python/example_code/sesv2/newsletter_scenario
excerpts:
- description:
genai: most
Expand Down Expand Up @@ -544,7 +588,7 @@ sesv2_NewsletterWorkflow:
Python:
versions:
- sdk_version: 3
github: python/example_code/sesv2
github: python/example_code/sesv2/newsletter_scenario
excerpts:
- description:
genai: most
Expand Down Expand Up @@ -581,3 +625,59 @@ sesv2_NewsletterWorkflow:
services:
sesv2: {CreateContactList, CreateContact, ListContacts, SendEmail.simple, SendEmail.template, CreateEmailIdentity, CreateEmailTemplate,
DeleteContactList, DeleteEmailIdentity, DeleteEmailTemplate}

sesv2_Hello:
title: Hello &SESv2;
title_abbrev: Hello &SESv2;
synopsis: get started using &SESv2;.
category: Hello
languages:
Python:
versions:
- sdk_version: 3
github: python/example_code/sesv2/attachments_scenario
excerpts:
- description:
snippet_tags:
- python.example_code.sesv2.Hello
services:
sesv2: {ListEmailIdentities}
sesv2_SendBulkEmail:
languages:
Python:
versions:
- sdk_version: 3
github: python/example_code/sesv2/attachments_scenario
excerpts:
- description:
snippet_tags:
- python.example_code.sesv2.SESv2Wrapper.decl
- python.example_code.sesv2.SendBulkEmail
services:
sesv2: {SendBulkEmail}
sesv2_Scenario_EmailAttachments:
title: Send emails with attachments using &SESv2;
title_abbrev: Email Attachments Scenario
synopsis: send emails with attachments using &SESv2;.
synopsis_list:
- Verify sender email identity.
- Create an email template for bulk sends.
- Send a simple email with a file attachment.
- Send a simple email with an inline image.
- Send bulk templated emails with attachments.
- Clean up resources.
category: Scenarios
languages:
Python:
versions:
- sdk_version: 3
github: python/example_code/sesv2/attachments_scenario
excerpts:
- description: Run an interactive scenario demonstrating email attachments.
snippet_tags:
- python.example_code.sesv2.Scenario_EmailAttachments
- description: Create an SESv2 wrapper class to manage operations.
snippet_tags:
- python.example_code.sesv2.SESv2Wrapper.class
services:
sesv2: {SendEmail, SendBulkEmail, CreateEmailIdentity, CreateEmailTemplate, GetEmailIdentity, DeleteEmailTemplate, DeleteEmailIdentity}
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -41,3 +41,4 @@ kotlin/services/**/.kotlin/
.kiro/settings/
.kiro/steering/

/codeloom_outputs
62 changes: 48 additions & 14 deletions gov2/s3/actions/bucket_basics.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,11 @@ import (
"io"
"log"
"os"
"sync"
"time"

"github.com/aws/aws-sdk-go-v2/aws"
"github.com/aws/aws-sdk-go-v2/feature/s3/manager"
"github.com/aws/aws-sdk-go-v2/feature/s3/transfermanager"
"github.com/aws/aws-sdk-go-v2/service/s3"
"github.com/aws/aws-sdk-go-v2/service/s3/types"
"github.com/aws/smithy-go"
Expand Down Expand Up @@ -162,15 +163,15 @@ func (basics BucketBasics) UploadFile(ctx context.Context, bucketName string, ob

// snippet-start:[gov2.s3.Upload]

// UploadLargeObject uses an upload manager to upload data to an object in a bucket.
// The upload manager breaks large data into parts and uploads the parts concurrently.
// UploadLargeObject uses the S3 transfer manager to upload data to an object in a bucket.
// The transfer manager breaks large data into parts and uploads the parts concurrently.
func (basics BucketBasics) UploadLargeObject(ctx context.Context, bucketName string, objectKey string, largeObject []byte) error {
largeBuffer := bytes.NewReader(largeObject)
var partMiBs int64 = 10
uploader := manager.NewUploader(basics.S3Client, func(u *manager.Uploader) {
u.PartSize = partMiBs * 1024 * 1024
tm := transfermanager.New(basics.S3Client, func(o *transfermanager.Options) {
o.PartSizeBytes = partMiBs * 1024 * 1024
})
_, err := uploader.Upload(ctx, &s3.PutObjectInput{
_, err := tm.UploadObject(ctx, &transfermanager.UploadObjectInput{
Bucket: aws.String(bucketName),
Key: aws.String(objectKey),
Body: largeBuffer,
Expand Down Expand Up @@ -234,18 +235,19 @@ func (basics BucketBasics) DownloadFile(ctx context.Context, bucketName string,

// snippet-start:[gov2.s3.Download]

// DownloadLargeObject uses a download manager to download an object from a bucket.
// The download manager gets the data in parts and writes them to a buffer until all of
// DownloadLargeObject uses the S3 transfer manager to download an object from a bucket.
// The transfer manager gets the data in parts and writes them to a buffer until all of
// the data has been downloaded.
func (basics BucketBasics) DownloadLargeObject(ctx context.Context, bucketName string, objectKey string) ([]byte, error) {
var partMiBs int64 = 10
downloader := manager.NewDownloader(basics.S3Client, func(d *manager.Downloader) {
d.PartSize = partMiBs * 1024 * 1024
tm := transfermanager.New(basics.S3Client, func(o *transfermanager.Options) {
o.PartSizeBytes = partMiBs * 1024 * 1024
})
buffer := manager.NewWriteAtBuffer([]byte{})
_, err := downloader.Download(ctx, buffer, &s3.GetObjectInput{
Bucket: aws.String(bucketName),
Key: aws.String(objectKey),
buffer := NewWriteAtBuffer([]byte{})
_, err := tm.DownloadObject(ctx, &transfermanager.DownloadObjectInput{
Bucket: aws.String(bucketName),
Key: aws.String(objectKey),
WriterAt: buffer,
})
if err != nil {
log.Printf("Couldn't download large object from %v:%v. Here's why: %v\n",
Expand All @@ -254,6 +256,38 @@ func (basics BucketBasics) DownloadLargeObject(ctx context.Context, bucketName s
return buffer.Bytes(), err
}

// WriteAtBuffer is a thread-safe in-memory io.WriterAt implementation.
type WriteAtBuffer struct {
buf []byte
m sync.Mutex
}

// NewWriteAtBuffer creates a new WriteAtBuffer with an initial byte slice.
func NewWriteAtBuffer(buf []byte) *WriteAtBuffer {
return &WriteAtBuffer{buf: buf}
}

// WriteAt writes len(p) bytes to the buffer starting at byte offset off.
func (b *WriteAtBuffer) WriteAt(p []byte, off int64) (int, error) {
b.m.Lock()
defer b.m.Unlock()
end := int(off) + len(p)
if end > len(b.buf) {
newBuf := make([]byte, end)
copy(newBuf, b.buf)
b.buf = newBuf
}
copy(b.buf[off:], p)
return len(p), nil
}

// Bytes returns the contents of the buffer.
func (b *WriteAtBuffer) Bytes() []byte {
b.m.Lock()
defer b.m.Unlock()
return b.buf
}

// snippet-end:[gov2.s3.Download]

// snippet-start:[gov2.s3.CopyObject]
Expand Down
2 changes: 1 addition & 1 deletion gov2/s3/cmd/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ import (
// Amazon Simple Storage Service (Amazon S3) actions to work with
// S3 buckets and objects.
// - `largeobjects` - Runs the interactive large objects scenario that shows you how to upload
// and download large objects by using a transfer manager.
// and download large objects by using the S3 transfer manager.
// - `presigning` - Runs the interactive presigning scenario that shows you how to
// get presigned requests that contain temporary credentials
// and can be used to make requests from any HTTP client.
Expand Down
2 changes: 1 addition & 1 deletion gov2/s3/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ go 1.24
require (
github.com/aws/aws-sdk-go-v2 v1.41.5
github.com/aws/aws-sdk-go-v2/config v1.27.33
github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.17.18
github.com/aws/aws-sdk-go-v2/feature/s3/transfermanager v0.1.18
github.com/aws/aws-sdk-go-v2/service/s3 v1.97.3
github.com/aws/smithy-go v1.24.2
github.com/awsdocs/aws-doc-sdk-examples/gov2/demotools v0.0.0-20240907001412-a9375541143b
Expand Down
4 changes: 2 additions & 2 deletions gov2/s3/scenarios/scenario_large_objects.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@ import (
// Simple Storage Service (Amazon S3) to upload and download large objects.
//
// 1. Create a bucket.
// 3. Upload a large object to the bucket by using an upload manager.
// 5. Download a large object by using a download manager.
// 3. Upload a large object to the bucket by using the S3 transfer manager.
// 5. Download a large object by using the S3 transfer manager.
// 8. Delete all objects in the bucket.
// 9. Delete the bucket.
//
Expand Down
2 changes: 1 addition & 1 deletion gov2/s3/scenarios/scenario_large_objects_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ func TestRunLargeObjectScenario(t *testing.T) {
testtools.RunScenarioTests(&scenTest, t)
}

// httpErr is used to mock an HTTP error. This is required by the download manager,
// httpErr is used to mock an HTTP error. This is required by the transfer manager,
// which calls GetObject until it receives a 415 status code.
type httpErr struct {
statusCode int
Expand Down
12 changes: 6 additions & 6 deletions gov2/workflows/s3_object_lock/actions/s3_actions.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import (
"time"

"github.com/aws/aws-sdk-go-v2/aws"
"github.com/aws/aws-sdk-go-v2/feature/s3/manager"
"github.com/aws/aws-sdk-go-v2/feature/s3/transfermanager"
"github.com/aws/aws-sdk-go-v2/service/s3"
"github.com/aws/aws-sdk-go-v2/service/s3/types"
"github.com/aws/smithy-go"
Expand All @@ -24,7 +24,7 @@ import (
// S3Actions wraps S3 service actions.
type S3Actions struct {
S3Client *s3.Client
S3Manager *manager.Uploader
S3Manager *transfermanager.Client
}

// snippet-end:[gov2.workflows.s3.ObjectLock.S3Actions.struct]
Expand Down Expand Up @@ -303,16 +303,16 @@ func (actor S3Actions) PutObjectRetention(ctx context.Context, bucket string, ke

// snippet-start:[gov2.workflows.s3.ObjectLock.UploadObject]

// UploadObject uses the S3 upload manager to upload an object to a bucket.
// UploadObject uses the S3 transfer manager to upload an object to a bucket.
func (actor S3Actions) UploadObject(ctx context.Context, bucket string, key string, contents string) (string, error) {
var outKey string
input := &s3.PutObjectInput{
input := &transfermanager.UploadObjectInput{
Bucket: aws.String(bucket),
Key: aws.String(key),
Body: bytes.NewReader([]byte(contents)),
ChecksumAlgorithm: types.ChecksumAlgorithmSha256,
ChecksumAlgorithm: "SHA256",
}
output, err := actor.S3Manager.Upload(ctx, input)
output, err := actor.S3Manager.UploadObject(ctx, input)
if err != nil {
var noBucket *types.NoSuchBucket
if errors.As(err, &noBucket) {
Expand Down
Loading
Loading