diff --git a/.gitignore b/.gitignore
index 3fc1d884b983db7cd48581b4198239e70ebc5119..174f39620a3a67eaad565eae9eaff3b03614809e 100644
--- a/.gitignore
+++ b/.gitignore
@@ -17,3 +17,4 @@ target/
 .idea
 *.iml
 *.orig
+.vscode/
diff --git a/lombok.config b/lombok.config
index d07dd9b0e2b0281fbf514a968b9451cb6af62f93..a06fa130e8af26b659f2d3a0cb1114cd966a9b0e 100644
--- a/lombok.config
+++ b/lombok.config
@@ -27,4 +27,5 @@ lombok.log.slf4j.flagUsage = ERROR
 lombok.log.log4j.flagUsage = ERROR
 lombok.data.flagUsage = ERROR
 lombok.nonNull.exceptionType = IllegalArgumentException
-lombok.addLombokGeneratedAnnotation = true
\ No newline at end of file
+lombok.addLombokGeneratedAnnotation = true
+lombok.copyableAnnotations += org.springframework.beans.factory.annotation.Qualifier
\ No newline at end of file
diff --git a/nachrichten-manager-interface/src/main/protobuf/antragraum.model.proto b/nachrichten-manager-interface/src/main/protobuf/antragraum.model.proto
index 34504138fbe034e800a6d2d02eeb90b78bac9f6f..ada0e22babb0fa9f35fb2f5c0980a7cb4cfd3719 100644
--- a/nachrichten-manager-interface/src/main/protobuf/antragraum.model.proto
+++ b/nachrichten-manager-interface/src/main/protobuf/antragraum.model.proto
@@ -62,9 +62,9 @@ message GrpcRueckfrage {
   string status = 7;
   string trustLevel = 8;
   bool accessible = 9;
-  
+
   string text = 10;
-  
+
   repeated string attachmentFileId = 11;
   repeated GrpcRueckfrageAnswer answers = 12;
 }
@@ -92,4 +92,30 @@ message GrpcGetRueckfrageRequest {
 
 message GrpcGetRueckfrageResponse {
   GrpcRueckfrage rueckfrage = 1;
+}
+
+message GrpcGetAttachmentContentRequest {
+  string samlToken = 1;
+  string nachrichtId = 2;
+  string fileId = 3;
+}
+
+message GrpcGetAttachmentContentResponse {
+  bytes fileContent = 1;
+}
+
+message GrpcGetAttachmentMetadataRequest {
+  string samlToken = 1;
+  string nachrichtId = 2;
+  string fileId = 3;
+}
+
+message GrpcGetAttachmentMetadataResponse {
+  GrpcFileMetadata fileMetadata = 1;
+}
+
+message GrpcFileMetadata {
+	string name = 1;
+	int64 size = 2;
+	string contentType = 3;
 }
\ No newline at end of file
diff --git a/nachrichten-manager-interface/src/main/protobuf/antragraum.proto b/nachrichten-manager-interface/src/main/protobuf/antragraum.proto
index e22f3bb0fa2226094b2551d8748c1095f1ded8f5..b82fb2711176118e1bc07819205dd9d7e5b63586 100644
--- a/nachrichten-manager-interface/src/main/protobuf/antragraum.proto
+++ b/nachrichten-manager-interface/src/main/protobuf/antragraum.proto
@@ -26,7 +26,6 @@ syntax = "proto3";
 package de.ozgcloud.nachrichten.antragraum;
 
 import "antragraum.model.proto";
-import "command.model.proto";
 
 option java_multiple_files = true;
 option java_package = "de.ozgcloud.nachrichten.antragraum";
@@ -38,7 +37,14 @@ service AntragraumService {
 
   rpc SendRueckfrageAnswer(GrpcSendRueckfrageAnswerRequest) returns (GrpcSendRueckfrageAnswerResponse) {
   }
-  
+
   rpc GetRueckfrage(GrpcGetRueckfrageRequest) returns (GrpcGetRueckfrageResponse){
   }
+
+  rpc GetAttachmentContent (GrpcGetAttachmentContentRequest) returns (stream GrpcGetAttachmentContentResponse){
+  }
+
+  rpc GetAttachmentMetadata (GrpcGetAttachmentMetadataRequest) returns (GrpcGetAttachmentMetadataResponse){
+  }
+
 }
\ No newline at end of file
diff --git a/nachrichten-manager-server/pom.xml b/nachrichten-manager-server/pom.xml
index daca1893bc2bb66e7e61a5398486ac054084c5a3..28fe26cba3bca3d69eafc29654f923ce7e366430 100644
--- a/nachrichten-manager-server/pom.xml
+++ b/nachrichten-manager-server/pom.xml
@@ -24,7 +24,8 @@
     unter der Lizenz sind dem Lizenztext zu entnehmen.
 
 -->
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
 	<modelVersion>4.0.0</modelVersion>
 
@@ -47,7 +48,8 @@
 		<bayernid-proxy-interface.version>0.7.0</bayernid-proxy-interface.version>
 		<vorgang-manager.version>2.17.0-SNAPSHOT</vorgang-manager.version>
 		<muk-postfach.version>0.1.0-SNAPSHOT</muk-postfach.version>
-		<ozgcloud-starter.version>0.13.0-SNAPSHOT</ozgcloud-starter.version>
+		<api-lib.version>0.13.0-SNAPSHOT</api-lib.version>
+		<ozgcloud-common.version>4.5.0-SNAPSHOT</ozgcloud-common.version>
 	</properties>
 
 	<dependencies>
@@ -86,12 +88,6 @@
 			<artifactId>muk-postfach</artifactId>
 			<version>${muk-postfach.version}</version>
 		</dependency>
-        
-        <dependency>
-			<groupId>de.ozgcloud.api-lib</groupId>
-			<artifactId>ozg-cloud-spring-boot-starter</artifactId>
-			<version>${ozgcloud-starter.version}</version>
-		</dependency>
 
 		<dependency>
 			<groupId>de.ozgcloud.info</groupId>
@@ -99,6 +95,18 @@
 			<version>${ozg-info-manager-interface.version}</version>
 		</dependency>
 
+		<dependency>
+			<groupId>de.ozgcloud.api-lib</groupId>
+			<artifactId>api-lib-core</artifactId>
+			<version>${api-lib.version}</version>
+		</dependency>
+
+		<dependency>
+			<groupId>de.ozgcloud.common</groupId>
+			<artifactId>ozgcloud-common-lib</artifactId>
+			<version>${ozgcloud-common.version}</version>
+		</dependency>
+
 		<dependency>
 			<groupId>org.springframework.boot</groupId>
 			<artifactId>spring-boot-starter-mail</artifactId>
@@ -221,6 +229,13 @@
 			<type>test-jar</type>
 			<scope>test</scope>
 		</dependency>
+		<dependency>
+			<groupId>de.ozgcloud.api-lib</groupId>
+			<artifactId>api-lib-core</artifactId>
+			<version>${api-lib.version}</version>
+			<type>test-jar</type>
+			<scope>test</scope>
+		</dependency>
 	</dependencies>
 
 	<build>
@@ -334,4 +349,4 @@
 			</snapshots>
 		</repository>
 	</repositories>
-</project>
+</project>
\ No newline at end of file
diff --git a/nachrichten-manager-server/src/main/java/de/ozgcloud/nachrichten/NachrichtenManagerConfiguration.java b/nachrichten-manager-server/src/main/java/de/ozgcloud/nachrichten/NachrichtenManagerConfiguration.java
index 26f1ff18efd89ac60df5af212f5f410cbb3a1732..7f8d749fcc4f46c569fdc72071ebf779a13282d2 100644
--- a/nachrichten-manager-server/src/main/java/de/ozgcloud/nachrichten/NachrichtenManagerConfiguration.java
+++ b/nachrichten-manager-server/src/main/java/de/ozgcloud/nachrichten/NachrichtenManagerConfiguration.java
@@ -6,6 +6,11 @@ import org.springframework.context.annotation.Configuration;
 import de.ozgcloud.apilib.common.command.OzgCloudCommandService;
 import de.ozgcloud.apilib.common.command.grpc.CommandMapper;
 import de.ozgcloud.apilib.common.command.grpc.GrpcOzgCloudCommandService;
+import de.ozgcloud.apilib.file.OzgCloudFileService;
+import de.ozgcloud.apilib.file.grpc.GrpcOzgCloudFileService;
+import de.ozgcloud.apilib.file.grpc.OzgCloudFileMapper;
+import de.ozgcloud.vorgang.grpc.binaryFile.BinaryFileServiceGrpc.BinaryFileServiceBlockingStub;
+import de.ozgcloud.vorgang.grpc.binaryFile.BinaryFileServiceGrpc.BinaryFileServiceStub;
 import de.ozgcloud.vorgang.grpc.command.CommandServiceGrpc;
 import net.devh.boot.grpc.client.inject.GrpcClient;
 
@@ -13,19 +18,33 @@ import net.devh.boot.grpc.client.inject.GrpcClient;
 public class NachrichtenManagerConfiguration {
 
 	public static final String OZG_CLOUD_COMMAND_SERVICE_NAME = "nachrichten_OzgCloudCommandService";
+	public static final String OZG_CLOUD_FILE_SERVICE_NAME = "nachrichten_OzgCloudFileService";
 
 	public static final String NACHRICHTEN_VORGANG_SERVICE = "nachrichten_vorgangService";
 	public static final String NACHRICHTEN_VORGANG_REMOTE_SERVICE = "nachrichten_vorgangRemoteService";
+	public static final String NACHRICHTEN_ATTACHED_ITEM_SERVICE = "nachrichten_attachedItemService";
+	public static final String NACHRICHTEN_OZG_CLOUD_FILE_MAPPER = "nachrichten_OzgCloudFileMapperImpl";
 
 	public static final String GRPC_VORGANG_MANAGER_NAME = "vorgang-manager";
 	public static final String GRPC_COMMAND_MANAGER_NAME = "command-manager";
+	public static final String GRPC_FILE_MANAGER_NAME = "file-manager";
 
 	@GrpcClient(GRPC_COMMAND_MANAGER_NAME)
 	private CommandServiceGrpc.CommandServiceBlockingStub commandServiceStub;
 
+	@GrpcClient(GRPC_FILE_MANAGER_NAME)
+	private BinaryFileServiceBlockingStub fileServiceBlockingStub;
+	@GrpcClient(GRPC_FILE_MANAGER_NAME)
+	private BinaryFileServiceStub fileServiceAsyncServiceStub;
+
 	@Bean(OZG_CLOUD_COMMAND_SERVICE_NAME)
 	OzgCloudCommandService grpcOzgCloudCommandService(CommandMapper commandMapper, NachrichtenManagerCallContextProvider contextProvider) {
 		return new GrpcOzgCloudCommandService(commandServiceStub, commandMapper, contextProvider,
 				GrpcOzgCloudCommandService.DEFAULT_COMMAND_REQUEST_THRESHOLD_MILLIS);
 	}
+
+	@Bean(OZG_CLOUD_FILE_SERVICE_NAME)
+	OzgCloudFileService grpcOzgCloudFileService(NachrichtenManagerCallContextProvider contextProvider, OzgCloudFileMapper mapper) {
+		return new GrpcOzgCloudFileService(fileServiceBlockingStub, fileServiceAsyncServiceStub, contextProvider, mapper);
+	}
 }
\ No newline at end of file
diff --git a/nachrichten-manager-server/src/main/java/de/ozgcloud/nachrichten/antragraum/AntragraumGrpcService.java b/nachrichten-manager-server/src/main/java/de/ozgcloud/nachrichten/antragraum/AntragraumGrpcService.java
index 60fb62d6bfa8384eb093780e82411474bec22373..3c1918cca9831e57400a8ed37c9b8374956505e7 100644
--- a/nachrichten-manager-server/src/main/java/de/ozgcloud/nachrichten/antragraum/AntragraumGrpcService.java
+++ b/nachrichten-manager-server/src/main/java/de/ozgcloud/nachrichten/antragraum/AntragraumGrpcService.java
@@ -28,11 +28,19 @@ import java.util.List;
 import java.util.stream.Stream;
 
 import org.apache.commons.lang3.StringUtils;
+import org.springframework.beans.factory.annotation.Qualifier;
 import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
+import org.springframework.core.task.TaskExecutor;
 
+import com.google.protobuf.ByteString;
+
+import de.ozgcloud.apilib.file.OzgCloudFile;
+import de.ozgcloud.common.binaryfile.GrpcBinaryFileServerDownloader;
 import de.ozgcloud.common.errorhandling.TechnicalException;
+import de.ozgcloud.nachrichten.NachrichtenManagerConfiguration;
 import de.ozgcloud.nachrichten.common.vorgang.VorgangService;
 import de.ozgcloud.nachrichten.postfach.PostfachNachricht;
+import io.grpc.stub.CallStreamObserver;
 import io.grpc.stub.StreamObserver;
 import lombok.RequiredArgsConstructor;
 import net.devh.boot.grpc.server.service.GrpcService;
@@ -41,9 +49,16 @@ import net.devh.boot.grpc.server.service.GrpcService;
 @RequiredArgsConstructor
 @ConditionalOnProperty(AntragraumProperties.PROPERTY_ANTRAGSRAUM_URL)
 class AntragraumGrpcService extends AntragraumServiceGrpc.AntragraumServiceImplBase {
+
+	static final int CHUNK_SIZE = 256 * 1024;
+
 	private final AntragraumService service;
 	private final AntragraumNachrichtMapper mapper;
 	private final RueckfrageMapper rueckfrageMapper;
+	private final AttachmentFileRequestMapper attachmentFileRequestMapper;
+	@Qualifier(NachrichtenManagerConfiguration.NACHRICHTEN_OZG_CLOUD_FILE_MAPPER)
+	private final OzgCloudFileMapper ozgCloudFileMapper;
+	private final TaskExecutor taskExecutor;
 
 	private final VorgangService vorgangService;
 
@@ -113,4 +128,38 @@ class AntragraumGrpcService extends AntragraumServiceGrpc.AntragraumServiceImplB
 	GrpcGetRueckfrageResponse buildGetRueckfrageResponse(GrpcRueckfrage rueckfrage) {
 		return GrpcGetRueckfrageResponse.newBuilder().setRueckfrage(rueckfrage).build();
 	}
+
+	@Override
+	public void getAttachmentContent(GrpcGetAttachmentContentRequest request, StreamObserver<GrpcGetAttachmentContentResponse> responseObserver) {
+		buildAttachmentDownloader(attachmentFileRequestMapper.fromContentRequest(request), responseObserver).start();
+	}
+
+	GrpcBinaryFileServerDownloader<GrpcGetAttachmentContentResponse> buildAttachmentDownloader(AttachmentFileRequest request,
+			StreamObserver<GrpcGetAttachmentContentResponse> responseObserver) {
+		return GrpcBinaryFileServerDownloader.<GrpcGetAttachmentContentResponse>builder()
+				.callObserver((CallStreamObserver<GrpcGetAttachmentContentResponse>) responseObserver)
+				.taskExecutor(taskExecutor)
+				.downloadConsumer(outputStream -> service.getAttachmentContent(request, outputStream))
+				.chunkBuilder(this::buildAttachmentChunkResponse)
+				.build();
+	}
+
+	GrpcGetAttachmentContentResponse buildAttachmentChunkResponse(ByteString chunk) {
+		return GrpcGetAttachmentContentResponse.newBuilder().setFileContent(chunk).build();
+	}
+
+	@Override
+	public void getAttachmentMetadata(GrpcGetAttachmentMetadataRequest request, StreamObserver<GrpcGetAttachmentMetadataResponse> responseObserver) {
+		var attachment = service.getAttachmentMetadata(attachmentFileRequestMapper.fromMetadataRequest(request));
+
+		responseObserver.onNext(buildAttachmentMetadataResponse(attachment));
+
+		responseObserver.onCompleted();
+	}
+
+	private GrpcGetAttachmentMetadataResponse buildAttachmentMetadataResponse(OzgCloudFile attachment) {
+		return GrpcGetAttachmentMetadataResponse.newBuilder()
+				.setFileMetadata(ozgCloudFileMapper.toMetadata(attachment))
+				.build();
+	}
 }
diff --git a/nachrichten-manager-server/src/main/java/de/ozgcloud/nachrichten/antragraum/AntragraumService.java b/nachrichten-manager-server/src/main/java/de/ozgcloud/nachrichten/antragraum/AntragraumService.java
index bbb328c92b80034e5edd6897b3b4f9f49c03fab7..315c455b75691aa841ccf8dec547d776ca800d73 100644
--- a/nachrichten-manager-server/src/main/java/de/ozgcloud/nachrichten/antragraum/AntragraumService.java
+++ b/nachrichten-manager-server/src/main/java/de/ozgcloud/nachrichten/antragraum/AntragraumService.java
@@ -25,6 +25,7 @@ package de.ozgcloud.nachrichten.antragraum;
 
 import static java.util.Objects.*;
 
+import java.io.OutputStream;
 import java.time.ZonedDateTime;
 import java.util.Comparator;
 import java.util.Optional;
@@ -41,10 +42,14 @@ import org.springframework.stereotype.Service;
 
 import de.ozgcloud.apilib.common.datatypes.GenericId;
 import de.ozgcloud.apilib.common.errorhandling.NotFoundException;
+import de.ozgcloud.apilib.file.OzgCloudFile;
+import de.ozgcloud.apilib.file.OzgCloudFileId;
+import de.ozgcloud.apilib.file.OzgCloudFileService;
 import de.ozgcloud.nachrichten.NachrichtenManagerConfiguration;
 import de.ozgcloud.nachrichten.NachrichtenManagerProperties;
 import de.ozgcloud.nachrichten.common.vorgang.Vorgang;
 import de.ozgcloud.nachrichten.common.vorgang.VorgangService;
+import de.ozgcloud.nachrichten.postfach.AttachedItemService;
 import de.ozgcloud.nachrichten.postfach.PersistPostfachNachrichtService;
 import de.ozgcloud.nachrichten.postfach.PostfachNachricht;
 import de.ozgcloud.nachrichten.postfach.PostfachNachrichtMapper;
@@ -57,6 +62,8 @@ import lombok.extern.log4j.Log4j2;
 @ConditionalOnProperty(AntragraumProperties.PROPERTY_ANTRAGSRAUM_URL)
 public class AntragraumService {
 
+	private static final String POSTFACH_NACHRICHT = "PostfachNachricht";
+
 	static final String BAYERN_ID_SERVICE_KONTO_TYPE = "BAYERN_ID";
 
 	static final String USER_NOTIFICATION_TEMPLATE = """
@@ -77,9 +84,15 @@ public class AntragraumService {
 
 	private final AntragraumProperties properties;
 	private final NachrichtenManagerProperties nachrichtenManagerProperties;
-	private final RueckfrageMapper rueckfrageMapper;
+
 	@Qualifier(NachrichtenManagerConfiguration.NACHRICHTEN_VORGANG_SERVICE)
 	private final VorgangService vorgangService;
+	@Qualifier(NachrichtenManagerConfiguration.OZG_CLOUD_FILE_SERVICE_NAME)
+	private final OzgCloudFileService ozgCloudFileService;
+	@Qualifier(NachrichtenManagerConfiguration.NACHRICHTEN_ATTACHED_ITEM_SERVICE)
+	private final AttachedItemService attachedItemService;
+
+	private final RueckfrageMapper rueckfrageMapper;
 	private final PostfachNachrichtMapper nachrichtMapper;
 
 	@PostConstruct
@@ -94,14 +107,14 @@ public class AntragraumService {
 		LOG.info("Starting Antragraum Service");
 	}
 
-	public String getAntragsraumUrl() {
-		return properties.getUrl();
-	}
-
 	public String getUserNotificationText() {
 		return USER_NOTIFICATION_TEMPLATE.formatted(getAntragsraumUrl());
 	}
 
+	public String getAntragsraumUrl() {
+		return properties.getUrl();
+	}
+
 	public Stream<RueckfrageHead> findRueckfragen(String samlToken) {
 		verifyToken(samlToken);
 
@@ -139,7 +152,7 @@ public class AntragraumService {
 
 	public String sendRueckfrageAnswer(String samlToken, String rueckfrageId, PostfachNachricht nachricht) {
 		verifyToken(samlToken);
-		verifyPostfachId(samlToken, nachricht);
+		verifyAccessToPostfach(samlToken, nachricht);
 
 		return postfachNachrichtService.persistAnswer(rueckfrageId, nachricht);
 	}
@@ -150,20 +163,33 @@ public class AntragraumService {
 		return postfachNachrichtService.findAnswers(BAYERN_ID_SERVICE_KONTO_TYPE, getPostfachId(samlToken), rueckfrageId);
 	}
 
-	String getPostfachId(String samlToken) {
-		return decrypter.decryptPostfachId(parser.parse(samlToken));
-	}
-
 	public PostfachNachricht getRueckfrage(String samlToken, String id) {
 		verifyToken(samlToken);
 
 		var nachricht = nachrichtMapper.fromMapToPostfachMail(postfachNachrichtService.getById(id));
 
-		verifyPostfachId(samlToken, nachricht);
+		verifyAccessToPostfach(samlToken, nachricht);
 
 		return nachricht;
 	}
 
+	public void getAttachmentContent(AttachmentFileRequest request, OutputStream outputStream) {
+		verifyAccessToFile(request);
+		ozgCloudFileService.writeFileDataToStream(OzgCloudFileId.from(request.getFileId()), outputStream);
+	}
+
+	public OzgCloudFile getAttachmentMetadata(AttachmentFileRequest request) {
+		verifyAccessToFile(request);
+		return ozgCloudFileService.getFile(OzgCloudFileId.from(request.getFileId()));
+	}
+
+	void verifyAccessToFile(AttachmentFileRequest request) {
+		verifyToken(request.getSamlToken());
+		var nachricht = attachedItemService.getPostfachNachricht(request.getNachrichtId());
+		verifyAccessToPostfach(request.getSamlToken(), nachricht);
+		verifyFileId(request.getFileId(), nachricht);
+	}
+
 	void verifyToken(String token) {
 		var errors = verifier.verify(token);
 		if (CollectionUtils.isNotEmpty(errors)) {
@@ -171,12 +197,25 @@ public class AntragraumService {
 		}
 	}
 
-	void verifyPostfachId(String samlToken, PostfachNachricht nachricht) {
+	void verifyAccessToPostfach(String token, PostfachNachricht nachricht) {
 		var vorgang = vorgangService.getVorgang(nachricht.getVorgangId());
+		verifyPostfachId(token, nachricht, vorgang);
+		verifyTrustLevel(token, nachricht, vorgang);
+	}
 
+	void verifyPostfachId(String samlToken, PostfachNachricht nachricht, Vorgang vorgang) {
 		if (!StringUtils.equals(vorgang.getPostfachId(), getPostfachId(samlToken))) {
-			LOG.info("PostfachId in token is not matching postfachId in vorgang.");
-			throw new NotFoundException(GenericId.from(nachricht.getId()), "PostfachNachricht");
+			throw new NotFoundException(GenericId.from(nachricht.getId()), POSTFACH_NACHRICHT);
+		}
+	}
+
+	String getPostfachId(String samlToken) {
+		return decrypter.decryptPostfachId(parser.parse(samlToken));
+	}
+
+	void verifyTrustLevel(String token, PostfachNachricht nachricht, Vorgang vorgang) {
+		if (!isAccessible(token, vorgang.getTrustLevel())) {
+			throw new NotFoundException(GenericId.from(nachricht.getId()), POSTFACH_NACHRICHT);
 		}
 	}
 
@@ -191,4 +230,10 @@ public class AntragraumService {
 	Response parseSamlToken(String samlToken) {
 		return parser.parse(samlToken);
 	}
+
+	void verifyFileId(String fileId, PostfachNachricht nachricht) {
+		if (!nachricht.getAttachments().contains(fileId)) {
+			throw new NotFoundException(GenericId.from(nachricht.getId()), POSTFACH_NACHRICHT);
+		}
+	}
 }
\ No newline at end of file
diff --git a/nachrichten-manager-server/src/main/java/de/ozgcloud/nachrichten/antragraum/AttachmentFileRequest.java b/nachrichten-manager-server/src/main/java/de/ozgcloud/nachrichten/antragraum/AttachmentFileRequest.java
new file mode 100644
index 0000000000000000000000000000000000000000..51d0c97c956d666c088f8ede9772fcac4cc4356c
--- /dev/null
+++ b/nachrichten-manager-server/src/main/java/de/ozgcloud/nachrichten/antragraum/AttachmentFileRequest.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2024.  Das Land Schleswig-Holstein
+ * vertreten durch den Ministerpräsidenten des Landes Schleswig-Holstein
+ * Staatskanzlei Abteilung Digitalisierung und zentrales IT-Management der Landesregierung
+ *
+ * Lizenziert unter der EUPL, Version 1.2 oder - sobald
+ * diese von der Europäischen Kommission genehmigt wurden -
+ * Folgeversionen der EUPL ("Lizenz");
+ * Sie dürfen dieses Werk ausschließlich gemäß
+ * dieser Lizenz nutzen.
+ * Eine Kopie der Lizenz finden Sie hier:
+ *
+ * https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12
+ *
+ * Sofern nicht durch anwendbare Rechtsvorschriften
+ * gefordert oder in schriftlicher Form vereinbart, wird
+ * die unter der Lizenz verbreitete Software "so wie sie
+ * ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN -
+ * ausdrücklich oder stillschweigend - verbreitet.
+ * Die sprachspezifischen Genehmigungen und Beschränkungen
+ * unter der Lizenz sind dem Lizenztext zu entnehmen.
+ */
+
+package de.ozgcloud.nachrichten.antragraum;
+
+import lombok.Builder;
+import lombok.EqualsAndHashCode;
+import lombok.Getter;
+
+@Builder
+@Getter
+@EqualsAndHashCode
+public class AttachmentFileRequest {
+
+	private String samlToken;
+	private String nachrichtId;
+	private String fileId;
+
+}
diff --git a/nachrichten-manager-server/src/main/java/de/ozgcloud/nachrichten/antragraum/AttachmentFileRequestMapper.java b/nachrichten-manager-server/src/main/java/de/ozgcloud/nachrichten/antragraum/AttachmentFileRequestMapper.java
new file mode 100644
index 0000000000000000000000000000000000000000..fc6bfb55868ba8e319f194c5bfa724e8fc8a49c9
--- /dev/null
+++ b/nachrichten-manager-server/src/main/java/de/ozgcloud/nachrichten/antragraum/AttachmentFileRequestMapper.java
@@ -0,0 +1,13 @@
+package de.ozgcloud.nachrichten.antragraum;
+
+import org.mapstruct.Mapper;
+import org.mapstruct.NullValueCheckStrategy;
+import org.mapstruct.ReportingPolicy;
+
+@Mapper(nullValueCheckStrategy = NullValueCheckStrategy.ALWAYS, unmappedTargetPolicy = ReportingPolicy.WARN)
+interface AttachmentFileRequestMapper {
+
+	AttachmentFileRequest fromContentRequest(GrpcGetAttachmentContentRequest request);
+
+	AttachmentFileRequest fromMetadataRequest(GrpcGetAttachmentMetadataRequest request);
+}
diff --git a/nachrichten-manager-server/src/main/java/de/ozgcloud/nachrichten/antragraum/OzgCloudFileMapper.java b/nachrichten-manager-server/src/main/java/de/ozgcloud/nachrichten/antragraum/OzgCloudFileMapper.java
new file mode 100644
index 0000000000000000000000000000000000000000..43ccf9a3988595c9b10b027473f3fc178688c4fd
--- /dev/null
+++ b/nachrichten-manager-server/src/main/java/de/ozgcloud/nachrichten/antragraum/OzgCloudFileMapper.java
@@ -0,0 +1,27 @@
+package de.ozgcloud.nachrichten.antragraum;
+
+import org.mapstruct.AnnotateWith;
+import org.mapstruct.AnnotateWith.Element;
+import org.mapstruct.Mapper;
+import org.mapstruct.Mapping;
+import org.mapstruct.NullValueCheckStrategy;
+import org.mapstruct.ReportingPolicy;
+import org.springframework.stereotype.Component;
+
+import de.ozgcloud.apilib.file.OzgCloudFile;
+import de.ozgcloud.nachrichten.NachrichtenManagerConfiguration;
+
+@AnnotateWith(value = Component.class, elements = @Element(strings = NachrichtenManagerConfiguration.NACHRICHTEN_OZG_CLOUD_FILE_MAPPER))
+@Mapper(nullValueCheckStrategy = NullValueCheckStrategy.ALWAYS, unmappedTargetPolicy = ReportingPolicy.WARN)
+interface OzgCloudFileMapper {
+
+	@Mapping(target = "mergeFrom", ignore = true)
+	@Mapping(target = "clearField", ignore = true)
+	@Mapping(target = "clearOneof", ignore = true)
+	@Mapping(target = "mergeUnknownFields", ignore = true)
+	@Mapping(target = "contentTypeBytes", ignore = true)
+	@Mapping(target = "nameBytes", ignore = true)
+	@Mapping(target = "unknownFields", ignore = true)
+	@Mapping(target = "allFields", ignore = true)
+	GrpcFileMetadata toMetadata(OzgCloudFile file);
+}
diff --git a/nachrichten-manager-server/src/main/java/de/ozgcloud/nachrichten/postfach/AttachedItemRemoteService.java b/nachrichten-manager-server/src/main/java/de/ozgcloud/nachrichten/postfach/AttachedItemRemoteService.java
index d854927466082238e4b4e09f111c53ff5cc0c453..d7607de3d693db332191ce174d6553d30a9fba32 100644
--- a/nachrichten-manager-server/src/main/java/de/ozgcloud/nachrichten/postfach/AttachedItemRemoteService.java
+++ b/nachrichten-manager-server/src/main/java/de/ozgcloud/nachrichten/postfach/AttachedItemRemoteService.java
@@ -35,6 +35,7 @@ import de.ozgcloud.nachrichten.common.grpc.NachrichtenCallContextAttachingInterc
 import de.ozgcloud.vorgang.common.GrpcProperty;
 import de.ozgcloud.vorgang.vorgangAttachedItem.GrpcFindVorgangAttachedItemRequest;
 import de.ozgcloud.vorgang.vorgangAttachedItem.GrpcVorgangAttachedItem;
+import de.ozgcloud.vorgang.vorgangAttachedItem.GrpcVorgangAttachedItemRequest;
 import de.ozgcloud.vorgang.vorgangAttachedItem.VorgangAttachedItemServiceGrpc.VorgangAttachedItemServiceBlockingStub;
 import net.devh.boot.grpc.client.inject.GrpcClient;
 
@@ -70,10 +71,6 @@ class AttachedItemRemoteService {
 		return response.getVorgangAttachedItemsList().stream().map(postfachNachrichtMapper::fromAttachedItem);
 	}
 
-	VorgangAttachedItemServiceBlockingStub getVorgangAttachedItemServiceStub() {
-		return vorgangAttachedItemServiceStub.withInterceptors(new NachrichtenCallContextAttachingInterceptor());
-	}
-
 	GrpcFindVorgangAttachedItemRequest buildFindRequest(String vorgangId) {
 		return GrpcFindVorgangAttachedItemRequest.newBuilder()
 				.setVorgangId(vorgangId)
@@ -81,4 +78,19 @@ class AttachedItemRemoteService {
 				.setItemName(ITEM_NAME)
 				.build();
 	}
+
+	public PostfachNachricht getPostfachNachrichtById(String postfachNachrichtId) {
+		var response = getVorgangAttachedItemServiceStub().getById(buildGetByIdRequest(postfachNachrichtId));
+		return postfachNachrichtMapper.fromAttachedItem(response.getVorgangAttachedItem());
+	}
+
+	VorgangAttachedItemServiceBlockingStub getVorgangAttachedItemServiceStub() {
+		return vorgangAttachedItemServiceStub.withInterceptors(new NachrichtenCallContextAttachingInterceptor());
+	}
+
+	GrpcVorgangAttachedItemRequest buildGetByIdRequest(String postfachNachrichtId) {
+		return GrpcVorgangAttachedItemRequest.newBuilder()
+				.setId(postfachNachrichtId)
+				.build();
+	}
 }
diff --git a/nachrichten-manager-server/src/main/java/de/ozgcloud/nachrichten/postfach/AttachedItemService.java b/nachrichten-manager-server/src/main/java/de/ozgcloud/nachrichten/postfach/AttachedItemService.java
new file mode 100644
index 0000000000000000000000000000000000000000..ffceed84d137e6293d94f8ded9ca5a1d3b7fe646
--- /dev/null
+++ b/nachrichten-manager-server/src/main/java/de/ozgcloud/nachrichten/postfach/AttachedItemService.java
@@ -0,0 +1,17 @@
+package de.ozgcloud.nachrichten.postfach;
+
+import org.springframework.stereotype.Service;
+
+import de.ozgcloud.nachrichten.NachrichtenManagerConfiguration;
+import lombok.RequiredArgsConstructor;
+
+@Service(NachrichtenManagerConfiguration.NACHRICHTEN_ATTACHED_ITEM_SERVICE)
+@RequiredArgsConstructor
+public class AttachedItemService {
+
+	private final AttachedItemRemoteService remoteService;
+
+	public PostfachNachricht getPostfachNachricht(String id) {
+		return remoteService.getPostfachNachrichtById(id);
+	}
+}
diff --git a/nachrichten-manager-server/src/test/java/de/ozgcloud/nachrichten/antragraum/AntragraumGrpcServiceTest.java b/nachrichten-manager-server/src/test/java/de/ozgcloud/nachrichten/antragraum/AntragraumGrpcServiceTest.java
index a3815062085899da5db72cba9430d03f317a8c93..cde69a9d74df8dc17d6fa5aedf4859282c59e717 100644
--- a/nachrichten-manager-server/src/test/java/de/ozgcloud/nachrichten/antragraum/AntragraumGrpcServiceTest.java
+++ b/nachrichten-manager-server/src/test/java/de/ozgcloud/nachrichten/antragraum/AntragraumGrpcServiceTest.java
@@ -24,13 +24,17 @@ import static org.assertj.core.api.Assertions.*;
 import static org.mockito.ArgumentMatchers.*;
 import static org.mockito.Mockito.*;
 
+import java.io.OutputStream;
 import java.time.ZonedDateTime;
 import java.time.temporal.ChronoUnit;
 import java.util.List;
 import java.util.Optional;
 import java.util.UUID;
+import java.util.function.Consumer;
+import java.util.function.Function;
 import java.util.stream.Stream;
 
+import org.junit.jupiter.api.AfterEach;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.DisplayName;
 import org.junit.jupiter.api.Nested;
@@ -39,8 +43,16 @@ import org.mockito.ArgumentCaptor;
 import org.mockito.Captor;
 import org.mockito.InjectMocks;
 import org.mockito.Mock;
+import org.mockito.MockedConstruction;
 import org.mockito.Spy;
+import org.springframework.core.task.TaskExecutor;
 
+import com.google.protobuf.ByteString;
+import com.thedeanda.lorem.LoremIpsum;
+
+import de.ozgcloud.apilib.file.OzgCloudFile;
+import de.ozgcloud.apilib.file.OzgCloudFileTestFactory;
+import de.ozgcloud.common.binaryfile.GrpcBinaryFileServerDownloader;
 import de.ozgcloud.common.errorhandling.TechnicalException;
 import de.ozgcloud.nachrichten.common.vorgang.GrpcServiceKontoTestFactory;
 import de.ozgcloud.nachrichten.common.vorgang.Vorgang;
@@ -49,6 +61,7 @@ import de.ozgcloud.nachrichten.common.vorgang.VorgangTestFactory;
 import de.ozgcloud.nachrichten.postfach.PostfachNachricht;
 import de.ozgcloud.nachrichten.postfach.PostfachNachrichtTestFactory;
 import de.ozgcloud.nachrichten.postfach.osi.MessageTestFactory;
+import io.grpc.stub.CallStreamObserver;
 import io.grpc.stub.StreamObserver;
 
 class AntragraumGrpcServiceTest {
@@ -62,9 +75,14 @@ class AntragraumGrpcServiceTest {
 	private AntragraumNachrichtMapper nachrichtMapper;
 	@Mock
 	private RueckfrageMapper rueckfrageMapper;
-
+	@Mock
+	private AttachmentFileRequestMapper attachmentFileRequestMapper;
 	@Mock
 	private VorgangService vorgangService;
+	@Mock
+	private OzgCloudFileMapper ozgCloudFileMapper;
+	@Mock
+	private TaskExecutor taskExecutor;
 
 	@DisplayName("Find rueckfragen")
 	@Nested
@@ -448,4 +466,202 @@ class AntragraumGrpcServiceTest {
 			assertThat(rueckfrageResponse.getRueckfrage()).isEqualTo(grpcRueckfrage);
 		}
 	}
+
+	@Nested
+	class TestGetAttachmentContent {
+
+		@Mock
+		private StreamObserver<GrpcGetAttachmentContentResponse> responseObserver;
+		@Mock
+		private GrpcBinaryFileServerDownloader<GrpcGetAttachmentContentResponse> downloader;
+
+		private final GrpcGetAttachmentContentRequest grpcRequest = GrpcGetAttachmentContentRequestTestFactory.create();
+		private final AttachmentFileRequest request = AttachmentFileRequestTestFactory.create();
+
+		@BeforeEach
+		void mock() {
+			when(attachmentFileRequestMapper.fromContentRequest(grpcRequest)).thenReturn(request);
+			doReturn(downloader).when(grpcService).buildAttachmentDownloader(request, responseObserver);
+		}
+
+		@Test
+		void shouldMapRequest() {
+			callGetAttachmentContent();
+
+			verify(attachmentFileRequestMapper).fromContentRequest(grpcRequest);
+		}
+
+		@Test
+		void shouldCallBuildAttachmentDownloader() {
+			callGetAttachmentContent();
+
+			verify(grpcService).buildAttachmentDownloader(request, responseObserver);
+		}
+
+		@Test
+		void shouldStartDownloader() {
+			callGetAttachmentContent();
+
+			verify(downloader).start();
+		}
+
+		private void callGetAttachmentContent() {
+			grpcService.getAttachmentContent(grpcRequest, responseObserver);
+		}
+	}
+
+	@Nested
+	class TestBuildAttachmentDownloader {
+		@Mock
+		private CallStreamObserver<GrpcGetAttachmentContentResponse> responseObserver;
+		@Mock
+		private OutputStream outputStream;
+
+		private MockedConstruction<GrpcBinaryFileServerDownloader> downloaderMockedConstruction;
+		private GrpcBinaryFileServerDownloader<GrpcGetAttachmentContentResponse> downloader;
+		private StreamObserver<GrpcGetAttachmentContentResponse> setResponseObserver;
+		private TaskExecutor setTaskExecutor;
+		private Consumer<OutputStream> setDownloadConsumer;
+		private Function<ByteString, GrpcGetAttachmentContentResponse> setChunkBuilder;
+
+		private final AttachmentFileRequest request = AttachmentFileRequestTestFactory.create();
+		private final ByteString chunk = ByteString.copyFromUtf8(LoremIpsum.getInstance().getWords(5));
+
+		@SuppressWarnings("unchecked")
+		@BeforeEach
+		void mock() {
+			downloaderMockedConstruction = mockConstruction(GrpcBinaryFileServerDownloader.class, (downloader, context) -> {
+				setResponseObserver = (StreamObserver<GrpcGetAttachmentContentResponse>) context.arguments().get(0);
+				setChunkBuilder = (Function<ByteString, GrpcGetAttachmentContentResponse>) context.arguments().get(1);
+				setDownloadConsumer = (Consumer<OutputStream>) context.arguments().get(2);
+				setTaskExecutor = (TaskExecutor) context.arguments().get(3);
+				this.downloader = downloader;
+			});
+		}
+
+		@AfterEach
+		void closeMock() {
+			downloaderMockedConstruction.close();
+		}
+
+		@Test
+		void shouldSetResponseObserver() {
+			callBuildAttachmentDownloader();
+
+			assertThat(setResponseObserver).isEqualTo(responseObserver);
+		}
+
+		@Test
+		void shouldSetTaskExecutor() {
+			callBuildAttachmentDownloader();
+
+			assertThat(setTaskExecutor).isEqualTo(taskExecutor);
+		}
+
+		@Test
+		void shouldSetDownloadConsumer() {
+			callBuildAttachmentDownloader();
+
+			setDownloadConsumer.accept(outputStream);
+
+			verify(service).getAttachmentContent(request, outputStream);
+		}
+
+		@Test
+		void shouldSetChunkBuilder() {
+			var response = GrpcGetAttachmentContentResponse.newBuilder().setFileContent(chunk).build();
+			doReturn(response).when(grpcService).buildAttachmentChunkResponse(chunk);
+			callBuildAttachmentDownloader();
+
+			var result = setChunkBuilder.apply(chunk);
+
+			assertThat(result).isEqualTo(response);
+		}
+
+		@Test
+		void shouldReturnDownloader() {
+			var returnedDownloader = callBuildAttachmentDownloader();
+
+			assertThat(returnedDownloader).isEqualTo(downloader);
+		}
+
+		private GrpcBinaryFileServerDownloader<GrpcGetAttachmentContentResponse> callBuildAttachmentDownloader() {
+			return grpcService.buildAttachmentDownloader(request, responseObserver);
+		}
+	}
+
+	@Nested
+	class TestBuildAttachmentChunkResponse {
+
+		private final ByteString chunk = ByteString.copyFromUtf8(LoremIpsum.getInstance().getWords(5));
+
+		@Test
+		void shouldReturnResponse() {
+			var expectedResponse = GrpcGetAttachmentContentResponse.newBuilder().setFileContent(chunk).build();
+
+			var result = grpcService.buildAttachmentChunkResponse(chunk);
+
+			assertThat(result).isEqualTo(expectedResponse);
+
+		}
+	}
+
+	@Nested
+	class TestGetAttachmentMetadata {
+
+		@Mock
+		private StreamObserver<GrpcGetAttachmentMetadataResponse> responseObserver;
+
+		private final GrpcGetAttachmentMetadataRequest grpcRequest = GrpcGetAttachmentMetadataRequestTestFactory.create();
+		private final AttachmentFileRequest request = AttachmentFileRequestTestFactory.create();
+		private final OzgCloudFile attachment = OzgCloudFileTestFactory.create();
+		private final GrpcFileMetadata metadata = GrpcFileMetadataTestFactory.create();
+
+		@BeforeEach
+		void mock() {
+			when(attachmentFileRequestMapper.fromMetadataRequest(grpcRequest)).thenReturn(request);
+			when(service.getAttachmentMetadata(request)).thenReturn(attachment);
+			when(ozgCloudFileMapper.toMetadata(attachment)).thenReturn(metadata);
+		}
+
+		@Test
+		void shouldMapRequest() {
+			callGetAttachmentMetadata();
+
+			verify(attachmentFileRequestMapper).fromMetadataRequest(grpcRequest);
+		}
+
+		@Test
+		void shouldCallServiceToGetMetadata() {
+			callGetAttachmentMetadata();
+
+			verify(service).getAttachmentMetadata(request);
+		}
+
+		@Test
+		void shouldMapMetadata() {
+			callGetAttachmentMetadata();
+
+			verify(ozgCloudFileMapper).toMetadata(attachment);
+		}
+
+		@Test
+		void shouldSendMetadata() {
+			callGetAttachmentMetadata();
+
+			verify(responseObserver).onNext(argThat((response) -> response.getFileMetadata().equals(metadata)));
+		}
+
+		@Test
+		void shouldCallOnCompleted() {
+			callGetAttachmentMetadata();
+
+			verify(responseObserver).onCompleted();
+		}
+
+		private void callGetAttachmentMetadata() {
+			grpcService.getAttachmentMetadata(grpcRequest, responseObserver);
+		}
+	}
+
 }
\ No newline at end of file
diff --git a/nachrichten-manager-server/src/test/java/de/ozgcloud/nachrichten/antragraum/AntragraumServiceTest.java b/nachrichten-manager-server/src/test/java/de/ozgcloud/nachrichten/antragraum/AntragraumServiceTest.java
index f5220ab82ed6c6dfa41fb8aba83a080aa1785837..ffda45abc90ea43778a91908668c572f9f671ca3 100644
--- a/nachrichten-manager-server/src/test/java/de/ozgcloud/nachrichten/antragraum/AntragraumServiceTest.java
+++ b/nachrichten-manager-server/src/test/java/de/ozgcloud/nachrichten/antragraum/AntragraumServiceTest.java
@@ -5,6 +5,7 @@ import static org.junit.jupiter.api.Assertions.*;
 import static org.mockito.ArgumentMatchers.*;
 import static org.mockito.Mockito.*;
 
+import java.io.OutputStream;
 import java.time.ZonedDateTime;
 import java.util.List;
 import java.util.Map;
@@ -22,17 +23,23 @@ import org.mockito.Spy;
 import org.opensaml.saml.saml2.core.Response;
 
 import de.ozgcloud.apilib.common.errorhandling.NotFoundException;
+import de.ozgcloud.apilib.file.OzgCloudFile;
+import de.ozgcloud.apilib.file.OzgCloudFileId;
+import de.ozgcloud.apilib.file.OzgCloudFileService;
+import de.ozgcloud.apilib.file.OzgCloudFileTestFactory;
 import de.ozgcloud.nachrichten.NachrichtenManagerProperties;
 import de.ozgcloud.nachrichten.common.vorgang.GrpcPostfachAddressTestFactory;
 import de.ozgcloud.nachrichten.common.vorgang.GrpcServiceKontoTestFactory;
 import de.ozgcloud.nachrichten.common.vorgang.Vorgang;
 import de.ozgcloud.nachrichten.common.vorgang.VorgangService;
 import de.ozgcloud.nachrichten.common.vorgang.VorgangTestFactory;
+import de.ozgcloud.nachrichten.postfach.AttachedItemService;
 import de.ozgcloud.nachrichten.postfach.PersistPostfachNachrichtService;
 import de.ozgcloud.nachrichten.postfach.PostfachNachricht;
 import de.ozgcloud.nachrichten.postfach.PostfachNachrichtMapper;
 import de.ozgcloud.nachrichten.postfach.PostfachNachrichtTestFactory;
 import de.ozgcloud.nachrichten.postfach.osi.MessageTestFactory;
+import lombok.SneakyThrows;
 
 class AntragraumServiceTest {
 
@@ -58,6 +65,10 @@ class AntragraumServiceTest {
 	private VorgangService vorgangService;
 	@Mock
 	private PostfachNachrichtMapper nachrichtMapper;
+	@Mock
+	private AttachedItemService attachedItemService;
+	@Mock
+	private OzgCloudFileService ozgCloudFileService;
 
 	@Nested
 	class TestGetAntragsraumUrl {
@@ -297,7 +308,7 @@ class AntragraumServiceTest {
 
 	@DisplayName("Send rueckfragen answers")
 	@Nested
-	class TestSendRueckfragenAnswers {
+	class TestSendRueckfrageAnswer {
 		static final String SAML_TOKEN = "TOKEN";
 		static final String RUECKFRAGE_ID = UUID.randomUUID().toString();
 		static final PostfachNachricht NACHRICHT = PostfachNachrichtTestFactory.create();
@@ -305,7 +316,7 @@ class AntragraumServiceTest {
 		@BeforeEach
 		void mock() {
 			doNothing().when(service).verifyToken(any());
-			doNothing().when(service).verifyPostfachId(any(), any());
+			doNothing().when(service).verifyAccessToPostfach(any(), any());
 		}
 
 		@Test
@@ -323,10 +334,10 @@ class AntragraumServiceTest {
 		}
 
 		@Test
-		void shouldVerifyPostfachId() {
+		void shouldVerifyAccessToPostfach() {
 			service.sendRueckfrageAnswer(SAML_TOKEN, RUECKFRAGE_ID, NACHRICHT);
 
-			verify(service).verifyPostfachId(SAML_TOKEN, NACHRICHT);
+			verify(service).verifyAccessToPostfach(SAML_TOKEN, NACHRICHT);
 		}
 	}
 
@@ -402,7 +413,7 @@ class AntragraumServiceTest {
 			when(nachrichtMapper.fromMapToPostfachMail(any())).thenReturn(nachricht);
 
 			doNothing().when(service).verifyToken(any());
-			doNothing().when(service).verifyPostfachId(any(), any());
+			doNothing().when(service).verifyAccessToPostfach(any(), any());
 		}
 
 		@Test
@@ -434,10 +445,10 @@ class AntragraumServiceTest {
 		}
 
 		@Test
-		void shouldCallVerifyPostfachId() {
+		void shouldCallVerifyAccessToPostfach() {
 			getRueckfrage();
 
-			verify(service).verifyPostfachId(samlToken, nachricht);
+			verify(service).verifyAccessToPostfach(samlToken, nachricht);
 		}
 
 		private PostfachNachricht getRueckfrage() {
@@ -445,32 +456,18 @@ class AntragraumServiceTest {
 		}
 	}
 
-	@DisplayName("Verify postfachId")
 	@Nested
 	class TestVerifyPostfachId {
 
-		private static final String SAML_TOKEN = "TOKEN";
-		private static final PostfachNachricht POSTFACH_NACHRICHT = PostfachNachrichtTestFactory.create();
-
-		@BeforeEach
-		void mock() {
-			when(vorgangService.getVorgang(any())).thenReturn(VorgangTestFactory.create());
-		}
-
-		@Test
-		void shouldCallVorgangService() {
-			doReturn(GrpcPostfachAddressTestFactory.STRING_BASED_IDENTIFIER_POSTFACH_ID_VALUE).when(service).getPostfachId(any());
-
-			service.verifyPostfachId(SAML_TOKEN, POSTFACH_NACHRICHT);
-
-			verify(vorgangService).getVorgang(MessageTestFactory.VORGANG_ID);
-		}
+		private final String SAML_TOKEN = "TOKEN";
+		private final PostfachNachricht POSTFACH_NACHRICHT = PostfachNachrichtTestFactory.create();
+		private final Vorgang vorgang = VorgangTestFactory.create();
 
 		@Test
 		void shouldGetPostfachIdFromToken() {
 			doReturn(GrpcPostfachAddressTestFactory.STRING_BASED_IDENTIFIER_POSTFACH_ID_VALUE).when(service).getPostfachId(any());
 
-			service.verifyPostfachId(SAML_TOKEN, POSTFACH_NACHRICHT);
+			service.verifyPostfachId(SAML_TOKEN, POSTFACH_NACHRICHT, vorgang);
 
 			verify(service).getPostfachId(SAML_TOKEN);
 		}
@@ -479,7 +476,7 @@ class AntragraumServiceTest {
 		void shouldThrowExceptionOnMismatchPostfachId() {
 			doReturn("not-matching-postfach-id").when(service).getPostfachId(any());
 
-			assertThatThrownBy(() -> service.verifyPostfachId(SAML_TOKEN, POSTFACH_NACHRICHT))
+			assertThatThrownBy(() -> service.verifyPostfachId(SAML_TOKEN, POSTFACH_NACHRICHT, vorgang))
 					.isInstanceOf(NotFoundException.class)
 					.hasMessageContaining("PostfachNachricht")
 					.hasMessageContaining(PostfachNachrichtTestFactory.ID);
@@ -489,7 +486,7 @@ class AntragraumServiceTest {
 		void shouldNotThrowExceptionOnMatchingPostfachId() {
 			doReturn(GrpcPostfachAddressTestFactory.STRING_BASED_IDENTIFIER_POSTFACH_ID_VALUE).when(service).getPostfachId(any());
 
-			assertDoesNotThrow(() -> service.verifyPostfachId(SAML_TOKEN, POSTFACH_NACHRICHT));
+			assertDoesNotThrow(() -> service.verifyPostfachId(SAML_TOKEN, POSTFACH_NACHRICHT, vorgang));
 		}
 	}
 
@@ -587,4 +584,217 @@ class AntragraumServiceTest {
 			assertThat(parseResponse).isEqualTo(response);
 		}
 	}
+
+	@Nested
+	class TestGetAttachmentContent {
+
+		@Mock
+		private OutputStream outputStream;
+
+		private final AttachmentFileRequest request = AttachmentFileRequestTestFactory.create();
+
+		@BeforeEach
+		void mock() {
+			doNothing().when(service).verifyAccessToFile(request);
+		}
+
+		@Test
+		void shouldCallVerifyAccessToFile() {
+			callGetAttachmentContent();
+
+			verify(service).verifyAccessToFile(request);
+		}
+
+		@Test
+		void shouldCallOzgCloudFileServiceToWriteData() {
+			callGetAttachmentContent();
+
+			verify(ozgCloudFileService).writeFileDataToStream(OzgCloudFileId.from(AttachmentFileRequestTestFactory.FILE_ID), outputStream);
+		}
+
+		@SneakyThrows
+		private void callGetAttachmentContent() {
+			service.getAttachmentContent(request, outputStream);
+		}
+	}
+
+	@Nested
+	class TestGetAttachmentMetadata {
+
+		private final AttachmentFileRequest request = AttachmentFileRequestTestFactory.create();
+
+		@BeforeEach
+		void mock() {
+			doNothing().when(service).verifyAccessToFile(request);
+		}
+
+		@Test
+		void shouldCallVerifyAccessToFile() {
+			callGetAttachmentMetadata();
+
+			verify(service).verifyAccessToFile(request);
+		}
+
+		@Test
+		void shouldCallOzgCloudFileServiceToGetFile() {
+			callGetAttachmentMetadata();
+
+			verify(ozgCloudFileService).getFile(OzgCloudFileId.from(AttachmentFileRequestTestFactory.FILE_ID));
+		}
+
+		@Test
+		void shouldReturnOzgCloudFile() {
+			var ozgCloudFile = OzgCloudFileTestFactory.create();
+			when(ozgCloudFileService.getFile(OzgCloudFileId.from(AttachmentFileRequestTestFactory.FILE_ID))).thenReturn(ozgCloudFile);
+
+			var result = callGetAttachmentMetadata();
+
+			assertThat(result).isEqualTo(ozgCloudFile);
+		}
+
+		private OzgCloudFile callGetAttachmentMetadata() {
+			return service.getAttachmentMetadata(request);
+		}
+	}
+
+	@Nested
+	class TestVerifyAccessToFile {
+
+		private final AttachmentFileRequest request = AttachmentFileRequestTestFactory.create();
+		private final PostfachNachricht nachricht = PostfachNachrichtTestFactory.create();
+
+		@BeforeEach
+		void mock() {
+			when(attachedItemService.getPostfachNachricht(AttachmentFileRequestTestFactory.NACHRICHT_ID)).thenReturn(nachricht);
+			doNothing().when(service).verifyAccessToPostfach(AttachmentFileRequestTestFactory.TOKEN, nachricht);
+			doNothing().when(service).verifyFileId(AttachmentFileRequestTestFactory.FILE_ID, nachricht);
+		}
+
+		@Test
+		void shouldVerifySamlToken() {
+			callVerifyAccessToFile();
+
+			verify(service).verifyToken(AttachmentFileRequestTestFactory.TOKEN);
+		}
+
+		@Test
+		void shouldCallAttachedItemServiceToGetPostfachNachricht() {
+			callVerifyAccessToFile();
+
+			verify(attachedItemService).getPostfachNachricht(AttachmentFileRequestTestFactory.NACHRICHT_ID);
+		}
+
+		@Test
+		void shouldCallVerifyAccessToPostfach() {
+			callVerifyAccessToFile();
+
+			verify(service).verifyAccessToPostfach(AttachmentFileRequestTestFactory.TOKEN, nachricht);
+		}
+
+		@Test
+		void shouldVerifyFileId() {
+			callVerifyAccessToFile();
+
+			verify(service).verifyFileId(AttachmentFileRequestTestFactory.FILE_ID, nachricht);
+		}
+
+		private void callVerifyAccessToFile() {
+			service.verifyAccessToFile(request);
+		}
+
+	}
+
+	@Nested
+	class TestVerifyAccessToPostfach {
+
+		private final PostfachNachricht nachricht = PostfachNachrichtTestFactory.create();
+		private final Vorgang vorgang = VorgangTestFactory.create();
+
+		@BeforeEach
+		void mock() {
+			when(vorgangService.getVorgang(MessageTestFactory.VORGANG_ID)).thenReturn(vorgang);
+			doNothing().when(service).verifyPostfachId(AttachmentFileRequestTestFactory.TOKEN, nachricht, vorgang);
+			doNothing().when(service).verifyTrustLevel(AttachmentFileRequestTestFactory.TOKEN, nachricht, vorgang);
+		}
+
+		@Test
+		void shouldCallVorgangService() {
+			verifyAccessToPostfach();
+
+			verify(vorgangService).getVorgang(MessageTestFactory.VORGANG_ID);
+		}
+
+		@Test
+		void shouldCallVerifyPostfachId() {
+			verifyAccessToPostfach();
+
+			verify(service).verifyPostfachId(AttachmentFileRequestTestFactory.TOKEN, nachricht, vorgang);
+		}
+
+		@Test
+		void shouldVerifyTrustLevel() {
+			verifyAccessToPostfach();
+
+			verify(service).verifyTrustLevel(AttachmentFileRequestTestFactory.TOKEN, nachricht, vorgang);
+		}
+
+		private void verifyAccessToPostfach() {
+			service.verifyAccessToPostfach(AttachmentFileRequestTestFactory.TOKEN, nachricht);
+		}
+	}
+
+	@Nested
+	class TestVerifyTrustLevel {
+
+		private final PostfachNachricht nachricht = PostfachNachrichtTestFactory.create();
+		private final Vorgang vorgang = VorgangTestFactory.create();
+
+		@Test
+		void shouldCallIsAccessible() {
+			doReturn(true).when(service).isAccessible(AttachmentFileRequestTestFactory.TOKEN, GrpcServiceKontoTestFactory.TRUST_LEVEL);
+
+			callVerifyTrustLevel();
+
+			verify(service).isAccessible(AttachmentFileRequestTestFactory.TOKEN, GrpcServiceKontoTestFactory.TRUST_LEVEL);
+		}
+
+		@Test
+		void shouldThrowExceptionOnNotAccessible() {
+			doReturn(false).when(service).isAccessible(AttachmentFileRequestTestFactory.TOKEN, GrpcServiceKontoTestFactory.TRUST_LEVEL);
+
+			assertThatThrownBy(() -> callVerifyTrustLevel())
+					.isInstanceOf(NotFoundException.class)
+					.hasMessageContaining("PostfachNachricht")
+					.hasMessageContaining(PostfachNachrichtTestFactory.ID);
+		}
+
+		@Test
+		void shouldNotThrowExceptionOnAccessible() {
+			doReturn(true).when(service).isAccessible(AttachmentFileRequestTestFactory.TOKEN, GrpcServiceKontoTestFactory.TRUST_LEVEL);
+
+			assertDoesNotThrow(() -> callVerifyTrustLevel());
+		}
+
+		private void callVerifyTrustLevel() {
+			service.verifyTrustLevel(AttachmentFileRequestTestFactory.TOKEN, nachricht, vorgang);
+		}
+	}
+
+	@Nested
+	class TestVerifyFileId {
+		private final PostfachNachricht nachricht = PostfachNachrichtTestFactory.create();
+
+		@Test
+		void shouldThrowExceptionOnNotMatchingFileId() {
+			assertThatThrownBy(() -> service.verifyFileId(PostfachNachrichtTestFactory.ATTACHMENT_FILE_ID + "wrong", nachricht))
+					.isInstanceOf(NotFoundException.class)
+					.hasMessageContaining("PostfachNachricht")
+					.hasMessageContaining(PostfachNachrichtTestFactory.ID);
+		}
+
+		@Test
+		void shouldNotThrowExceptionOnMatchingFileId() {
+			assertDoesNotThrow(() -> service.verifyFileId(PostfachNachrichtTestFactory.ATTACHMENT_FILE_ID, nachricht));
+		}
+	}
 }
\ No newline at end of file
diff --git a/nachrichten-manager-server/src/test/java/de/ozgcloud/nachrichten/antragraum/AttachmentFileRequestMapperTest.java b/nachrichten-manager-server/src/test/java/de/ozgcloud/nachrichten/antragraum/AttachmentFileRequestMapperTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..f76b44c73d7bce9d9cc5ac1ec877f6cdfdfb8d94
--- /dev/null
+++ b/nachrichten-manager-server/src/test/java/de/ozgcloud/nachrichten/antragraum/AttachmentFileRequestMapperTest.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2024.  Das Land Schleswig-Holstein
+ * vertreten durch den Ministerpräsidenten des Landes Schleswig-Holstein
+ * Staatskanzlei Abteilung Digitalisierung und zentrales IT-Management der Landesregierung
+ *
+ * Lizenziert unter der EUPL, Version 1.2 oder - sobald
+ * diese von der Europäischen Kommission genehmigt wurden -
+ * Folgeversionen der EUPL ("Lizenz");
+ * Sie dürfen dieses Werk ausschließlich gemäß
+ * dieser Lizenz nutzen.
+ * Eine Kopie der Lizenz finden Sie hier:
+ *
+ * https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12
+ *
+ * Sofern nicht durch anwendbare Rechtsvorschriften
+ * gefordert oder in schriftlicher Form vereinbart, wird
+ * die unter der Lizenz verbreitete Software "so wie sie
+ * ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN -
+ * ausdrücklich oder stillschweigend - verbreitet.
+ * Die sprachspezifischen Genehmigungen und Beschränkungen
+ * unter der Lizenz sind dem Lizenztext zu entnehmen.
+ */
+
+package de.ozgcloud.nachrichten.antragraum;
+
+import static org.assertj.core.api.Assertions.*;
+
+import org.junit.jupiter.api.Nested;
+import org.junit.jupiter.api.Test;
+import org.mapstruct.factory.Mappers;
+
+class AttachmentFileRequestMapperTest {
+
+	private final AttachmentFileRequestMapper mapper = Mappers.getMapper(AttachmentFileRequestMapper.class);
+
+	@Nested
+	class TestFromContentRequest {
+
+		@Test
+		void shouldMapToRueckfrageAttachmentFileRequest() {
+			var request = mapper.fromContentRequest(GrpcGetAttachmentContentRequestTestFactory.create());
+
+			assertThat(request).isEqualTo(AttachmentFileRequestTestFactory.create());
+		}
+	}
+
+	@Nested
+	class TestFromMetadataRequest {
+
+		@Test
+		void shouldMapToRueckfrageAttachmentFileRequest() {
+			var request = mapper.fromMetadataRequest(GrpcGetAttachmentMetadataRequestTestFactory.create());
+
+			assertThat(request).isEqualTo(AttachmentFileRequestTestFactory.create());
+		}
+	}
+}
diff --git a/nachrichten-manager-server/src/test/java/de/ozgcloud/nachrichten/antragraum/AttachmentFileRequestTestFactory.java b/nachrichten-manager-server/src/test/java/de/ozgcloud/nachrichten/antragraum/AttachmentFileRequestTestFactory.java
new file mode 100644
index 0000000000000000000000000000000000000000..5697bb2a54e2c74d72868c78ef8a36654c8aa6fa
--- /dev/null
+++ b/nachrichten-manager-server/src/test/java/de/ozgcloud/nachrichten/antragraum/AttachmentFileRequestTestFactory.java
@@ -0,0 +1,27 @@
+package de.ozgcloud.nachrichten.antragraum;
+
+import java.util.UUID;
+
+import com.thedeanda.lorem.LoremIpsum;
+
+import de.ozgcloud.nachrichten.antragraum.AttachmentFileRequest.AttachmentFileRequestBuilder;
+import de.ozgcloud.nachrichten.postfach.PostfachNachrichtTestFactory;
+
+public class AttachmentFileRequestTestFactory {
+
+	public static final String TOKEN = LoremIpsum.getInstance().getWords(1);
+	public static final String FILE_ID = UUID.randomUUID().toString();
+	public static final String NACHRICHT_ID = PostfachNachrichtTestFactory.ID;
+
+	public static AttachmentFileRequest create() {
+		return createBuilder()
+				.build();
+	}
+
+	public static AttachmentFileRequestBuilder createBuilder() {
+		return AttachmentFileRequest.builder()
+				.samlToken(TOKEN)
+				.fileId(FILE_ID)
+				.nachrichtId(NACHRICHT_ID);
+	}
+}
diff --git a/nachrichten-manager-server/src/test/java/de/ozgcloud/nachrichten/antragraum/GrpcFileMetadataTestFactory.java b/nachrichten-manager-server/src/test/java/de/ozgcloud/nachrichten/antragraum/GrpcFileMetadataTestFactory.java
new file mode 100644
index 0000000000000000000000000000000000000000..41b231bf773e24e74b3e2800a4c39eaaa2c66c67
--- /dev/null
+++ b/nachrichten-manager-server/src/test/java/de/ozgcloud/nachrichten/antragraum/GrpcFileMetadataTestFactory.java
@@ -0,0 +1,23 @@
+package de.ozgcloud.nachrichten.antragraum;
+
+import de.ozgcloud.apilib.file.OzgCloudFileTestFactory;
+import de.ozgcloud.nachrichten.antragraum.GrpcFileMetadata.Builder;
+
+public class GrpcFileMetadataTestFactory {
+
+	public static final long SIZE = OzgCloudFileTestFactory.SIZE;
+	public static final String NAME = OzgCloudFileTestFactory.NAME;
+	public static final String CONTENT_TYPE = OzgCloudFileTestFactory.CONTENT_TYPE;
+
+	public static GrpcFileMetadata create() {
+		return createBuilder().build();
+
+	}
+
+	public static Builder createBuilder() {
+		return GrpcFileMetadata.newBuilder()
+				.setContentType(CONTENT_TYPE)
+				.setName(NAME)
+				.setSize(SIZE);
+	}
+}
diff --git a/nachrichten-manager-server/src/test/java/de/ozgcloud/nachrichten/antragraum/GrpcGetAttachmentContentRequestTestFactory.java b/nachrichten-manager-server/src/test/java/de/ozgcloud/nachrichten/antragraum/GrpcGetAttachmentContentRequestTestFactory.java
new file mode 100644
index 0000000000000000000000000000000000000000..51ac2d5f80248b21f2158161070aa9822fdf6f1b
--- /dev/null
+++ b/nachrichten-manager-server/src/test/java/de/ozgcloud/nachrichten/antragraum/GrpcGetAttachmentContentRequestTestFactory.java
@@ -0,0 +1,19 @@
+package de.ozgcloud.nachrichten.antragraum;
+
+public class GrpcGetAttachmentContentRequestTestFactory {
+
+	public static final String TOKEN = AttachmentFileRequestTestFactory.TOKEN;
+	public static final String FILE_ID = AttachmentFileRequestTestFactory.FILE_ID;
+	public static final String NACHRICHT_ID = AttachmentFileRequestTestFactory.NACHRICHT_ID;
+
+	public static GrpcGetAttachmentContentRequest create() {
+		return createBuilder().build();
+	}
+
+	public static GrpcGetAttachmentContentRequest.Builder createBuilder() {
+		return GrpcGetAttachmentContentRequest.newBuilder()
+				.setSamlToken(TOKEN)
+				.setNachrichtId(NACHRICHT_ID)
+				.setFileId(FILE_ID);
+	}
+}
diff --git a/nachrichten-manager-server/src/test/java/de/ozgcloud/nachrichten/antragraum/GrpcGetAttachmentMetadataRequestTestFactory.java b/nachrichten-manager-server/src/test/java/de/ozgcloud/nachrichten/antragraum/GrpcGetAttachmentMetadataRequestTestFactory.java
new file mode 100644
index 0000000000000000000000000000000000000000..bbd7acd1af4a4c27cf6cfb9c6698c2760241ab27
--- /dev/null
+++ b/nachrichten-manager-server/src/test/java/de/ozgcloud/nachrichten/antragraum/GrpcGetAttachmentMetadataRequestTestFactory.java
@@ -0,0 +1,19 @@
+package de.ozgcloud.nachrichten.antragraum;
+
+public class GrpcGetAttachmentMetadataRequestTestFactory {
+
+	public static final String TOKEN = AttachmentFileRequestTestFactory.TOKEN;
+	public static final String FILE_ID = AttachmentFileRequestTestFactory.FILE_ID;
+	public static final String NACHRICHT_ID = AttachmentFileRequestTestFactory.NACHRICHT_ID;
+
+	public static GrpcGetAttachmentMetadataRequest create() {
+		return createBuilder().build();
+	}
+
+	public static GrpcGetAttachmentMetadataRequest.Builder createBuilder() {
+		return GrpcGetAttachmentMetadataRequest.newBuilder()
+				.setSamlToken(TOKEN)
+				.setNachrichtId(NACHRICHT_ID)
+				.setFileId(FILE_ID);
+	}
+}
diff --git a/nachrichten-manager-server/src/test/java/de/ozgcloud/nachrichten/antragraum/OzgCloudFileMapperTest.java b/nachrichten-manager-server/src/test/java/de/ozgcloud/nachrichten/antragraum/OzgCloudFileMapperTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..cd64a2b0fa4ecd0817594a179598d6d2a4805b07
--- /dev/null
+++ b/nachrichten-manager-server/src/test/java/de/ozgcloud/nachrichten/antragraum/OzgCloudFileMapperTest.java
@@ -0,0 +1,25 @@
+package de.ozgcloud.nachrichten.antragraum;
+
+import static org.assertj.core.api.Assertions.*;
+
+import org.junit.jupiter.api.Nested;
+import org.junit.jupiter.api.Test;
+import org.mapstruct.factory.Mappers;
+
+import de.ozgcloud.apilib.file.OzgCloudFileTestFactory;
+
+class OzgCloudFileMapperTest {
+
+	private final OzgCloudFileMapper mapper = Mappers.getMapper(OzgCloudFileMapper.class);
+
+	@Nested
+	class TestToMetadata {
+
+		@Test
+		void shouldMapToMetadata() {
+			var metadata = mapper.toMetadata(OzgCloudFileTestFactory.create());
+
+			assertThat(metadata).isEqualTo(GrpcFileMetadataTestFactory.create());
+		}
+	}
+}
diff --git a/nachrichten-manager-server/src/test/java/de/ozgcloud/nachrichten/postfach/AttachedItemRemoteServiceTest.java b/nachrichten-manager-server/src/test/java/de/ozgcloud/nachrichten/postfach/AttachedItemRemoteServiceTest.java
index 0c879370f9fc9d636ca233686e98a63d69f816d5..62969f468a20003d0446dd1d345f32f6c39d625a 100644
--- a/nachrichten-manager-server/src/test/java/de/ozgcloud/nachrichten/postfach/AttachedItemRemoteServiceTest.java
+++ b/nachrichten-manager-server/src/test/java/de/ozgcloud/nachrichten/postfach/AttachedItemRemoteServiceTest.java
@@ -46,6 +46,8 @@ import de.ozgcloud.vorgang.common.GrpcProperty;
 import de.ozgcloud.vorgang.vorgangAttachedItem.GrpcFindVorgangAttachedItemRequest;
 import de.ozgcloud.vorgang.vorgangAttachedItem.GrpcFindVorgangAttachedItemResponse;
 import de.ozgcloud.vorgang.vorgangAttachedItem.GrpcVorgangAttachedItem;
+import de.ozgcloud.vorgang.vorgangAttachedItem.GrpcVorgangAttachedItemRequest;
+import de.ozgcloud.vorgang.vorgangAttachedItem.GrpcVorgangAttachedItemResponse;
 import de.ozgcloud.vorgang.vorgangAttachedItem.VorgangAttachedItemServiceGrpc.VorgangAttachedItemServiceBlockingStub;
 
 class AttachedItemRemoteServiceTest {
@@ -264,4 +266,75 @@ class AttachedItemRemoteServiceTest {
 			assertThat(postfachNachrichten).containsExactly(postfachNachricht);
 		}
 	}
+
+	@Nested
+	class TestGetPostfachNachrichtById {
+
+		@Mock
+		private VorgangAttachedItemServiceBlockingStub stubWithInterceptor;
+
+		private final GrpcVorgangAttachedItemRequest request = GrpcVorgangAttachedItemRequestTestFactory.create();
+		private final GrpcVorgangAttachedItemResponse response = GrpcVorgangAttachedItemResponseTestFactory.create();
+
+		@BeforeEach
+		void mock() {
+			doReturn(stubWithInterceptor).when(service).getVorgangAttachedItemServiceStub();
+			doReturn(request).when(service).buildGetByIdRequest(PostfachNachrichtTestFactory.ID);
+			when(stubWithInterceptor.getById(request)).thenReturn(response);
+		}
+
+		@Test
+		void shouldCallGetVorgangAttachedItemServiceStub() {
+			callGetPostfachNachrichtById();
+
+			verify(service).getVorgangAttachedItemServiceStub();
+		}
+
+		@Test
+		void shouldCallBuildGetByIdRequest() {
+			callGetPostfachNachrichtById();
+
+			verify(service).buildGetByIdRequest(PostfachNachrichtTestFactory.ID);
+		}
+
+		@Test
+		void shouldCallServiceStubWithInterceptor() {
+			callGetPostfachNachrichtById();
+
+			verify(stubWithInterceptor).getById(request);
+		}
+
+		@Test
+		void shouldMapToPostfachNachricht() {
+			callGetPostfachNachrichtById();
+
+			verify(postfachNachrichtMapper).fromAttachedItem(GrpcVorgangAttachedItemResponseTestFactory.ATTACHED_ITEM);
+		}
+
+		@Test
+		void shouldReturnMappedPostfachNachricht() {
+			var mappedPostfachNachricht = PostfachNachrichtTestFactory.create();
+			when(postfachNachrichtMapper.fromAttachedItem(GrpcVorgangAttachedItemResponseTestFactory.ATTACHED_ITEM))
+					.thenReturn(mappedPostfachNachricht);
+
+			var postfachNachricht = callGetPostfachNachrichtById();
+
+			assertThat(postfachNachricht).isEqualTo(mappedPostfachNachricht);
+		}
+
+		private PostfachNachricht callGetPostfachNachrichtById() {
+			return service.getPostfachNachrichtById(PostfachNachrichtTestFactory.ID);
+		}
+	}
+
+	@Nested
+	class TestBuildGetByIdRequest {
+
+		@Test
+		void shouldReturnGrpcRequest() {
+			var request = service.buildGetByIdRequest(PostfachNachrichtTestFactory.ID);
+
+			assertThat(request).isEqualTo(GrpcVorgangAttachedItemRequestTestFactory.create());
+		}
+	}
 }
\ No newline at end of file
diff --git a/nachrichten-manager-server/src/test/java/de/ozgcloud/nachrichten/postfach/AttachedItemServiceTest.java b/nachrichten-manager-server/src/test/java/de/ozgcloud/nachrichten/postfach/AttachedItemServiceTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..6c513319ac59889f9c3478bcf05d1dbfe7f70b2a
--- /dev/null
+++ b/nachrichten-manager-server/src/test/java/de/ozgcloud/nachrichten/postfach/AttachedItemServiceTest.java
@@ -0,0 +1,45 @@
+package de.ozgcloud.nachrichten.postfach;
+
+import static org.assertj.core.api.Assertions.*;
+import static org.mockito.Mockito.*;
+
+import org.junit.jupiter.api.Nested;
+import org.junit.jupiter.api.Test;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+
+class AttachedItemServiceTest {
+
+	@InjectMocks
+	private AttachedItemService service;
+
+	@Mock
+	private AttachedItemRemoteService remoteService;
+
+	@Nested
+	class TestGetPostfachNachricht {
+
+		private final PostfachNachricht postfachNachricht = PostfachNachrichtTestFactory.create();
+
+		@Test
+		void shouldCallRemoteService() {
+			callGetPostfachNachricht();
+
+			verify(remoteService).getPostfachNachrichtById(PostfachNachrichtTestFactory.ID);
+		}
+
+		@Test
+		void shouldReturnPostfachNachricht() {
+			when(remoteService.getPostfachNachrichtById(PostfachNachrichtTestFactory.ID)).thenReturn(postfachNachricht);
+
+			var result = callGetPostfachNachricht();
+
+			assertThat(result).isEqualTo(postfachNachricht);
+		}
+
+		private PostfachNachricht callGetPostfachNachricht() {
+			return service.getPostfachNachricht(PostfachNachrichtTestFactory.ID);
+		}
+	}
+
+}
diff --git a/nachrichten-manager-server/src/test/java/de/ozgcloud/nachrichten/postfach/GrpcVorgangAttachedItemRequestTestFactory.java b/nachrichten-manager-server/src/test/java/de/ozgcloud/nachrichten/postfach/GrpcVorgangAttachedItemRequestTestFactory.java
new file mode 100644
index 0000000000000000000000000000000000000000..2f371dd485369072b0e7b36aafa917c2eb469966
--- /dev/null
+++ b/nachrichten-manager-server/src/test/java/de/ozgcloud/nachrichten/postfach/GrpcVorgangAttachedItemRequestTestFactory.java
@@ -0,0 +1,16 @@
+package de.ozgcloud.nachrichten.postfach;
+
+import de.ozgcloud.vorgang.vorgangAttachedItem.GrpcVorgangAttachedItemRequest;
+import de.ozgcloud.vorgang.vorgangAttachedItem.GrpcVorgangAttachedItemRequest.Builder;
+
+public class GrpcVorgangAttachedItemRequestTestFactory {
+
+	public static GrpcVorgangAttachedItemRequest create() {
+		return createBuilder().build();
+	}
+
+	public static Builder createBuilder() {
+		return GrpcVorgangAttachedItemRequest.newBuilder()
+				.setId(PostfachNachrichtTestFactory.ID);
+	}
+}
diff --git a/nachrichten-manager-server/src/test/java/de/ozgcloud/nachrichten/postfach/GrpcVorgangAttachedItemResponseTestFactory.java b/nachrichten-manager-server/src/test/java/de/ozgcloud/nachrichten/postfach/GrpcVorgangAttachedItemResponseTestFactory.java
new file mode 100644
index 0000000000000000000000000000000000000000..ad87b1859ce2cd0e2bd47a7b468a31aae735983e
--- /dev/null
+++ b/nachrichten-manager-server/src/test/java/de/ozgcloud/nachrichten/postfach/GrpcVorgangAttachedItemResponseTestFactory.java
@@ -0,0 +1,19 @@
+package de.ozgcloud.nachrichten.postfach;
+
+import de.ozgcloud.vorgang.vorgangAttachedItem.GrpcVorgangAttachedItem;
+import de.ozgcloud.vorgang.vorgangAttachedItem.GrpcVorgangAttachedItemResponse;
+import de.ozgcloud.vorgang.vorgangAttachedItem.GrpcVorgangAttachedItemResponse.Builder;
+
+public class GrpcVorgangAttachedItemResponseTestFactory {
+
+	public static final GrpcVorgangAttachedItem ATTACHED_ITEM = GrpcVorgangAttachedItemTestFactory.create();
+
+	public static GrpcVorgangAttachedItemResponse create() {
+		return createBuilder().build();
+	}
+
+	public static Builder createBuilder() {
+		return GrpcVorgangAttachedItemResponse.newBuilder()
+				.setVorgangAttachedItem(ATTACHED_ITEM);
+	}
+}