Generate PDF and attach to Gmail:MIME Multipart request flutter web app - flutter

The requirement is to generate a receipt in the form of pdf and send an email to the user using Gmail API. I am able to send attachment but not attachment and message together (multipart). Here is the dart code written for a web app. If I add base64Str - i.e. bytes generated from pdf in the contentMultiPart, it simply creates pdf of base64 string. Hence I am attaching to body externally. Please help with Multipart MIME message.
class AdminCredentials {
final String? email;
final String? accessToken;
final String? idToken;
AdminCredentials(this.email, this.accessToken, {this.idToken});
}
generatepdf() async {
final pdf = pw.Document();
pdf.addPage(pw.Page(
pageFormat: PdfPageFormat.a4,
build: (pw.Context context) {
return pw.Center(
child: pw.Text("Hello World"),
); // Center
})); // Page
final bytes = await pdf.save();
return bytes;
}
sendEmail(AdminCredentials? adminCredentials) async {
Map<String, String> header = {};
header['Authorization'] = 'Bearer ${adminCredentials!.accessToken}';
header['Accept'] = 'application/json';
header['Content-type'] = 'application/json';
var pdfbytes = await generatepdf();
final base64Str = base64Encode(pdfbytes);
var from = adminCredentials.email;
var to = "test#gmail.com";
var subject ='Receipt';
var message = '<h1>Receipt generated against your flat </h1>\n<p>Dear Sir/Madam,<br/><br/>Thanks for your payment. Please find attached the receipt generated against your flat <br/><br/>Thanks and regards<br/>Office</p>';
var contentMultiPart = '''
MIME-Version: 1.0
Content-Transfer-Encoding: 7bit
Content-Type: multipart/mixed; charset="UTF-8"; boundary="part";
to: ${to}
from: ${from}
subject: ${subject}
--part
Content-Type: application/pdf; charset="base64"; Content-Disposition=application; name=receipt.pdf;
--part
Content-Type: text/html; charset="us-ascii";
$message
--part--
''';
List<int> bytes = utf8.encode(contentMultiPart);
String base64 = base64Encode(bytes);
var body = json.encode({'raw': base64+base64Str});
String apiUrl = 'https://www.googleapis.com/gmail/v1/users/' + from! + '/messages/send?uploadType=multipart';
Uri uri = Uri.parse(apiUrl);
final http.Response response = await http.post(uri, headers: header, body: body);
debugPrint('Response send');
print(json.decode(response.body));
if (response.statusCode != 200) {
final Map<String, dynamic> data = json.decode(response.body);
print('error: ' + response.statusCode.toString());
print(data);
return false;
} else {
print('ok: ' + response.statusCode.toString());
print('ok: ' + response.headers.toString());
return true;
}
}

Related

I have to send emails using particular gmail account in flutter

I want to send an email using a particular email address. But in my app first I sign in using google and then send emails using Gmail API using logged in user auth-headers.
But in this, anyone can log in and send emails. but I want only a particular email can send emails from my app. So I statically store auth headers for that particular email and sending email but my problem is that auth headers is expire after some time.
Here my code for google sign In:
GoogleSignIn googleSignIn = new GoogleSignIn(
scopes: <String>['https://www.googleapis.com/auth/gmail.send'],
);
await googleSignIn.signIn().then((data) async {
await data.authHeaders.then((result) async {
var header = {
'Authorization': result['Authorization'],
'X-Goog-AuthUser': result['X-Goog-AuthUser']
};
await testingEmail(data.email, header);
});
});
Code for send email:
Future<Null> testingEmail(String userId, Map header) async {
header['Content-type'] = 'application/json';
var from = userId;
var to = 'email in which send email';
var subject = 'subject of mail';
var message = 'Body of email';
var content = '''
Content-Type: text/plain; charset="us-ascii"
MIME-Version: 1.0
Content-Transfer-Encoding: 7bit
to: $to
from: 'Email alias name <$from>'
subject: $subject
$message''';
var bytes = utf8.encode(content);
var base64 = base64Encode(bytes);
var body = json.encode({'raw': base64});
String url = 'https://www.googleapis.com/gmail/v1/users/' +
userId +
'/messages/send';
final http.Response response =
await http.post(url, headers: header, body: body);
if (response.statusCode != 200) {
return Future.error("Something went wrong");
}
}
Help me to sort out this problem
You can refresh your token
Future<String> getRefreshToken()async{
if(_auth?.currentUser() !=null){
// print("user----------${_auth.currentUser()}");
FirebaseUser user = await _auth?.currentUser();
if(user !=null){
dynamic value = await user?.getIdToken(refresh: true);
String tokenValue = value?.token;
return tokenValue;
}
return null;
}
return null;
}

How to upload image to server API with Flutter [duplicate]

This question already has an answer here:
Upload image with http.post and registration form in Flutter?
(1 answer)
Closed 3 years ago.
I am new to Flutter development. My problem is that I try to upload the image but I keep getting failed request.
This piece of code is where I connect it with a server API which will receive the image file from Flutter. String attachment which consist of the image path that is passed from createIncident function located at another page.
Future<IncidentCreateResponse> createIncident( String requesterName, String requesterEmail,
String requesterMobile, String attachment, String title,
String tags, String body, String teamId,
String address ) async {
IncidentCreateResponse incidentCreateResponse;
var url = GlobalConfig.API_BASE_HANDESK + GlobalConfig.API_INCIDENT_CREATE_TICKETS;
var token = Auth().loginSession.accessToken;
var postBody = new Map<String, dynamic>();
postBody["requester_name"] = requesterName;
postBody["requester_email"] = requesterEmail;
postBody["requester_mobile_no"] = requesterMobile;
postBody["attachment"] = attachment;
postBody["title"] = title;
postBody["tags"] = tags;
postBody["body"] = body;
postBody["teamId"] = teamId;
postBody["address"] = address;
// Await the http get response, then decode the json-formatted responce.
var response = await http.post(
url,
body: postBody,
headers: {
'X-APP-ID': GlobalConfig.APP_ID,
"Accept": "application/json; charset=UTF-8",
// "Content-Type": "application/x-www-form-urlencoded",
HttpHeaders.authorizationHeader: 'Bearer $token',
'token': GlobalConfig.API_INCIDENT_REPORT_TOKEN
}
);
if ((response.statusCode == 200) || (response.statusCode == 201)) {
print(response.body);
var data = json.decode(response.body);
incidentCreateResponse = IncidentCreateResponse.fromJson(data['data']);
} else {
print("createIncident failed with status: ${response.statusCode}.");
incidentCreateResponse = null;
}
return incidentCreateResponse;
}
This is the code snippet where I get the image path from the selected image from the gallery
Future getImageFromGallery(BuildContext context) async {
var picture = await ImagePicker.pickImage(source: ImageSource.gallery);
setState((){
_imageFile = picture;
attachment = basename(_imageFile.path);
});
Navigator.of(context).pop();
}
This is the code where I passed the attachment string to the HTTP Response
this.incidentService.createIncident(
Auth().loginSession.name,
Auth().loginSession.email,
Auth().loginSession.mobile_no,
this.attachment,
this._titleController.text,
this._tags,
this._contentController.text,
this._teamId,
this._addressController.text
).then((IncidentCreateResponse res) {
if (res != null) {
print('Ticket Id: ' + res.id);
// Navigator.pop(context);
this._successSubmittionDialog(context);
} else {
this._errorSubmittionDialog(context);
}
}
You can upload image using multipart or base64 Encode.
For uploading image using multipart Visit the Official documentation
For uploading image using base64 Encode you can checkout the Tutorial Here
I suggest using multipart image upload as it is even reliable when your image or files are larger in size.
Hope this could help you,
create a function to upload your image after picking or clicking an image like,
Future<ResponseModel> uploadPhoto(
String _token,
File _image,
String _path,
) async {
Dio dio = new Dio();
FormData _formdata = new FormData();
_formdata.add("photo", new UploadFileInfo(_image, _path));
final response = await dio.post(
baseUrl + '/image/upload',
data: _formdata,
options: Options(
method: 'POST',
headers: {
authTokenHeader: _token,
},
responseType: ResponseType.json,
),
);
if (response.statusCode == 200 || response.statusCode == 500) {
return ResponseModel.fromJson(json.decode(response.toString()));
} else {
throw Exception('Failed to upload!');
}
}
then you can use use uploadImage,
uploadImage(_token, _image,_image.uri.toFilePath()).then((ResponseModel response) {
//do something with the response
});
I have used Dio for the task, you can find more detail about dio here
Add this to your package's pubspec.yaml file:
dependencies:
dio: ^3.0.5
Then import it in your Dart code, you can use:
import 'package:dio/dio.dart';
To upload image using multipart API use this code ie
Add this library dio in your project in pubspec.yaml file
dio: ^3.0.5
and import this in your class
import 'package:dio/dio.dart';
Declare this variable in your class like State<CustomClass>
static var uri = "BASE_URL_HERE";
static BaseOptions options = BaseOptions(
baseUrl: uri,
responseType: ResponseType.plain,
connectTimeout: 30000,
receiveTimeout: 30000,
validateStatus: (code) {
if (code >= 200) {
return true;
}
});
static Dio dio = Dio(options);
then use this method to upload file
Future<dynamic> _uploadFile() async {
try {
Options options = Options(
//contentType: ContentType.parse('application/json'), // only for json type api
);
var directory = await getExternalStorageDirectory(); // directory path
final path = await directory.path; // path of the directory
Response response = await dio.post('/update_profile',
data: FormData.from({
"param_key": "value",
"param2_key": "value",
"param3_key": "value",
"profile_pic_param_key": UploadFileInfo(File("$path/pic.jpg"), "pic.jpg"),
}),
options: options);
setState(() {
isLoading = false;
});
if (response.statusCode == 200 || response.statusCode == 201) {
var responseJson = json.decode(response.data);
return responseJson;
} else if (response.statusCode == 401) {
print(' response code 401');
throw Exception("Incorrect Email/Password");
} else
throw Exception('Authentication Error');
} on DioError catch (exception) {
if (exception == null ||
exception.toString().contains('SocketException')) {
throw Exception("Network Error");
} else if (exception.type == DioErrorType.RECEIVE_TIMEOUT ||
exception.type == DioErrorType.CONNECT_TIMEOUT) {
throw Exception(
"Could'nt connect, please ensure you have a stable network.");
} else {
return null;
}
}
}

How do I upload image in Flutter App to my server and decode the json response from the server?

I have an Endpoint on my server which accepts multipart/form-data and sends back json as a response.
I want to send an Image from my flutter App to my server and Decode the json received from the server.
You can use http.MultipartRequest for that
Example:-
static Future<UploadImageRes> uploadImage(int id, File imageFile) async {
if (imageFile != null) {
var stream = new http.ByteStream(imageFile.openRead());
var length = await imageFile.length();
String token = PreferenceUtils.getString(AppConstants.LOGGED_IN);
var uri = Uri.parse(UrlConstants.ADD_RECIPE_PHOTO);
LogUtils.d("====uri : $uri");
LogUtils.d("====recipeId : $id");
var request = new http.MultipartRequest("POST", uri);
String fileName = imageFile.path.split("/").last;
var multipartFile = new http.MultipartFile('photo', stream, length,
filename: fileName, contentType: new MediaType('image', 'jpeg'));
request.headers.addAll({"Authorization": "Bearer $token"});
request.files.add(multipartFile);
request.fields["recipeId"] = "$id";
var response = await request.send();
var statusCode = response.statusCode;
LogUtils.d("====statusCode : $statusCode");
if (statusCode < 200 || statusCode >= 400) {
throw new ApiException("Uploading failed");
}
final respStr = await response.stream.bytesToString();
return Future.value(UploadImageRes.fromJson(JsonDecoder().convert(respStr)));
} else {
throw new ApiException("Uploading failed");
}
}
In final respStr = await response.stream.bytesToString(); you will get your api response

how to upload image to rest API in flutter through http post method?

I'm trying to upload an image through the flutter via post method. and I'm using image_picker for pick file from mobile but I can't able to upload
and I have tried to send the file like FormData that also doesn't work
Future<dynamic> uploadLicence(int id ,dynamic obj) async {
FormData formdata = new FormData(); // just like JS
formdata.add("image",obj);
final response = await post('Logistic/driver/LicenceImage?
driverId=$id',
formdata);
print(response);
// return null;
if (response.statusCode == 200) {
final result = json.decode(response.body);
return result;
} else {
return null;
}
}
after that, I just tried with this method but this also not working
Future<dynamic> uploadLicence(int id, File file) async {
final url = Uri.parse('$BASE_URL/Logistic/driver/LicenceImage?
driverId=$id');
final fileName = path.basename(file.path);
final bytes = await compute(compress, file.readAsBytesSync());
var request = http.MultipartRequest('POST', url)
..files.add(new http.MultipartFile.fromBytes(
'image',bytes,filename: fileName,);
var response = await request.send();
var decoded = await
response.stream.bytesToString().then(json.decode);
if (response.statusCode == HttpStatus.OK) {
print("image uploded $decoded");
} else {
print("image uplod failed ");
}
}
List<int> compress(List<int> bytes) {
var image = img.decodeImage(bytes);
var resize = img.copyResize(image);
return img.encodePng(resize, level: 1);
}
It's possible with MultipartRequest. Or you can use simply dio package. It's one command.
With http:
import 'package:http/http.dart' as http;
final Uri uri = Uri.parse(url);
final http.MultipartRequest request = http.MultipartRequest("POST", uri);
// Additional key-values here
request.fields['sample'] = variable;
// Adding the file, field is the key for file and file is the value
request.files.add(http.MultipartFile.fromBytes(
field, await file.readAsBytes(), filename: filename);
// progress track of uploading process
final http.StreamedResponse response = await request.send();
print('statusCode => ${response.statusCode}');
// checking response data
Map<String, dynamic> data;
await for (String s in response.stream.transform(utf8.decoder)) {
data = jsonDecode(s);
print('data: $data');
}
I user this code for my project i hope work for you
Upload(File imageFile) async {
var stream = new http.ByteStream(DelegatingStream.typed(imageFile.openRead()));
var length = await imageFile.length();
var uri = Uri.parse(uploadURL);
var request = new http.MultipartRequest("POST", uri);
var multipartFile = new http.MultipartFile('file', stream, length,
filename: basename(imageFile.path));
//contentType: new MediaType('image', 'png'));
request.files.add(multipartFile);
var response = await request.send();
print(response.statusCode);
response.stream.transform(utf8.decoder).listen((value) {
print(value);
});
}

How to set list<String> in body http.post

in postman body:
id:2
images[]:image1 base64
image[]:image2 base64
how to set body to send request?
this my code
var uri = 'url';
var images = List<String>();
Map data = {
'id': id,
'images[]' : images,
};
var body = json.encode(data);
final response = await http.post(uri, body: body);
print("${response.statusCode}");
print("${response.body}");
if (response.statusCode == 200) {
return Model.fromJson(json.decode(response.body));
} else {
throw Exception('Failed to load post');
}
response is failed
what's wrong with my code?