I found dart plugin called mailer3: "^1.1.9". Previously I create an image in mobile temp directory. In Flutter mobile app I try to send this saved picture using mailer3 plugin as a mail. The mail reach the destination, I don't get error but seems lost the attachment in process.
In dart it works very well and send the attachment as well. In flutter I can use the temp directory to show the image in app but cannot be able attache to mail.
The image location is in the temp folder of the device:
'/data/user/0/com.myApp.myApp/app_flutter/20180700087.jpg'
I can show the image using below code:
new FileImage(File('$newDekontImage'),
Error:
E/flutter (21184): [ERROR:topaz/lib/tonic/logging/dart_error.cc(16)] Unhandled exception:
E/flutter (21184): FileSystemException: Cannot open file, path = '/data/user/0/com.myApp.myApp/app_flutter/20180700087.jpg' (OS Error: No such file or directory, errno = 2)
How to send mail with attachments in Flutter with provided information in this question?
The Flutter Code:
// TODO: SEND MAIL
void _sendMail() async {
if (!_formKey.currentState.validate()) {
return;
} else {
_formKey.currentState.save();
var _options = new GmailSmtpOptions()
..username = “mymailaddress#gmail.com"
..password = “myPassword”;
var _emailTransport = new SmtpTransport(_options);
var _envelope = new Envelope()
..from = "mymailaddress#gmail.com"
..recipients.add(_receiverMailAddress)
..subject = "${_userDekontDetails[0][0].toString()} - Receipt”
..attachments.add(await new Attachment(file: await new File('$newDekontImage')))
..text = "${_userDekontDetails[0][0].toString()} - Receipt"
..html = '<h3>${_userDekontDetails[0][0].toString()} Receipt.</h3>'
'<p>Hi, registered under my name, I am sending the receipt (${widget._currentUserReceiptNo}) with attached to this mail.</p>'
'<p></p>'
'<h5>Regards, </br></h5>'
'${_userDekontDetails[0][0].toString()}';
_emailTransport.send(_envelope)
..then((envelope) => print('Email sent'))
..catchError((e) => print('Error occured: $e'));
}
}
As of this writing, the mailer3 plugin is outdated and mailer is the most up-to-date plugin for sending emails. The mailer plugin currently contains important fixes that mailer2 and mailer3 has. I suggest opting to use mailer package instead of mailer3.
Here's a port of your code snippet from mailer3 to mailer
_sendMail(String username, String accessToken) async {
// Read https://pub.dev/documentation/mailer/latest/smtp_server_gmail/gmailSaslXoauth2.html
var _emailTransport = gmailSaslXoauth2(username, accessToken);
var _envelope = new Message()
..from = "mymailaddress#gmail.com"
..recipients.add("recepient#gmail.com")
..subject = '{EMAIL_SUBJECT_GOES_HERE}'
// Read https://pub.dev/documentation/mailer/latest/mailer/FileAttachment-class.html
..attachments
.add(FileAttachment(File('{FILE_PATH}')))
..text = '{PLAIN_TEXT_GOES_HERE}'
..html = '{HTML_CONTENT_GOES_HERE}';
send(_envelope, _emailTransport)
..then((envelope) => print('Email sent'))
..catchError((e) => print('Error occured: $e'));
}
I have used enough_mail, Hope it will be helpful.
MessageBuilder messageBuilder = MessageBuilder();
Future<bool> onFileSelect(BuildContext context) async {
final result = await FilePicker.platform
.pickFiles(type: FileType.any, allowMultiple: true, withData: true);
if (result == null) {
return false;
}
for (final file in result.files) {
final lastDotIndex = file.path.lastIndexOf('.');
MediaType mediaType;
if (lastDotIndex == -1 || lastDotIndex == file.path.length - 1) {
mediaType = MediaType.fromSubtype(MediaSubtype.applicationOctetStream);
} else {
final ext = file.path.substring(lastDotIndex + 1);
mediaType = MediaType.guessFromFileExtension(ext);
}
messageBuilder.addBinary(file.bytes, mediaType, filename: file.name);
}
return true;
}
Future<void> sendMail(BuildContext buildContext) async {
setState(() {
needToFreezeUi = true;
});
MySnackBar.show(buildContext, MySnackBar.loadingIcon, "Please wait...!");
SmtpClient smtpClient = SmtpClient(domain, isLogEnabled: true);
try {
await smtpClient.connectToServer(
"$serverPrefix.${userInfo.domainName}",
smtpServerPort,
isSecure: isSmtpServerSecure
);
await smtpClient.ehlo();
await smtpClient.authenticate(userInfo.email, userInfo.password);
messageBuilder.from = [MailAddress('', userInfo.email)];
messageBuilder.to = [MailAddress('', toTextEditCtl.text)];
messageBuilder.cc = selectedCCEmailInfos.map((e) => MailAddress('',e.emailAddress)).toList();
messageBuilder.bcc = selectedBCCEmailInfos.map((e) => MailAddress('',e.emailAddress)).toList();
messageBuilder.subject = subjectTextEditCtl.text;
String htmlText = await htmlEditorController.getText();
messageBuilder.addTextHtml(htmlText);
messageBuilder.hasAttachments ? messageBuilder.getPart(
MediaSubtype.multipartAlternative,
recursive: false
) : messageBuilder.addPart(
mediaSubtype: MediaSubtype.multipartAlternative,
insert: true
);
if (!messageBuilder.hasAttachments) {
messageBuilder.setContentType(
MediaType.fromSubtype(MediaSubtype.multipartAlternative)
);
}
MimeMessage mimeMessage = messageBuilder.buildMimeMessage();
SmtpResponse smtpResponse = await smtpClient.sendMessage(mimeMessage);
MySnackBar.hide(buildContext);
if(smtpResponse.isOkStatus){
MySnackBar.show(buildContext,MySnackBar.successIcon,"Mail send successfully");
clearInputFields(buildContext);
}else {
MySnackBar.show(buildContext,MySnackBar.errorIcon,"Something went wrong, please try again!");
}
} on SmtpException catch (e) {
MySnackBar.show(buildContext,MySnackBar.errorIcon,"Something went wrong, please try again!");
}
setState(() {
needToFreezeUi = false;
});
}
============================
dependencies:
enough_mail: ^1.3.4
html_editor_enhanced: ^1.4.0
file_picker: ^3.0.2+2
Related
I tried to mix remote audio tracks in one track and replace my local stream but I got the following error
InvalidStateError: Media stream has no audio tracks createMediaStreamSource
Note: This happen in IOS and I used sipjs, angular , Ionic, and IOSRTC
async mixNWayCall(nawayCall: NWayCall) {
var receivedTracks = [];
nawayCall.lines.forEach((line: Line) => {
if (line !== null && line !== undefined) {
const sessionDescriptionHandler = line.sipSession.sessionDescriptionHandler;
if (!(sessionDescriptionHandler instanceof Web.SessionDescriptionHandler)) {
throw new Error("Session's session description handler not instance of SessionDescriptionHandler.");
}
const peerConnection = sessionDescriptionHandler.peerConnection;
if (!peerConnection) {
throw new Error("Peer connection closed.");
}
peerConnection.getReceivers().forEach((receiver) => {
if (receiver.track) {
receivedTracks.push(receiver.track);
}
});
}
});
let context = new AudioContext();
let allReceivedMediaStreams = new MediaStream();
nawayCall.lines.forEach((line: Line) => {
if (line !== null && line !== undefined) {
let mixedOutput = context.createMediaStreamDestination();
const sessionDescriptionHandler = line.sipSession.sessionDescriptionHandler;
if (!(sessionDescriptionHandler instanceof Web.SessionDescriptionHandler)) {
throw new Error("Session's session description handler not instance of SessionDescriptionHandler.");
}
const senderPeerConnection = sessionDescriptionHandler.peerConnection;
if (!senderPeerConnection) { throw new Error("Peer connection closed."); }
senderPeerConnection.getReceivers().forEach((receiver) => {
receivedTracks.forEach((track) => {
allReceivedMediaStreams.addTrack(receiver.track);
console.log(receiver.track.id, ' receiver.track.id');
console.log(track.id, ' track.id');
if (receiver.track.id !== track.id) {
var sourceStream = context.createMediaStreamSource(new MediaStream([track]));
sourceStream.connect(mixedOutput);
}
});
});
senderPeerConnection.getSenders().forEach((sender) => {
nawayCall.mergeTracks.push(sender.track);
let senderSourceStream = context.createMediaStreamSource(new MediaStream([sender.track]));
senderSourceStream.connect(mixedOutput);
sender.replaceTrack(mixedOutput.stream.getTracks()[0])
});
senderPeerConnection.getSenders()[0].replaceTrack(mixedOutput.stream.getTracks()[0]);
}
});
nawayCall.lines.forEach(async (line: Line) => {
if (line.held) await this.lineService.onResume(line.id, true);
});
nawayCall.held = false;
if (nawayCall.media.mute)
await this.lineService.onNWayCallUnmute(nawayCall.id);
}
}
from the code in the description I got an error that no audio tracks and
I expected to mix audio tracks in one audio track then merge the call
Is there some one who can really help here?
I can't get anything from sso.getGraphData in the office addin generated from Yeoman generator.
Here is my code in ssoauthhelper.js:
export async function getGraphData() {
try {
let bootstrapToken = await OfficeRuntime.auth.getAccessToken({ allowSignInPrompt: true });
let exchangeResponse = await sso.getGraphToken(bootstrapToken);
if (exchangeResponse.claims) {
// Microsoft Graph requires an additional form of authentication. Have the Office host
// get a new token using the Claims string, which tells AAD to prompt the user for all
// required forms of authentication.
let mfaBootstrapToken = await OfficeRuntime.auth.getAccessToken({ authChallenge: exchangeResponse.claims });
exchangeResponse = sso.getGraphToken(mfaBootstrapToken);
}
if (exchangeResponse.error) {
// AAD errors are returned to the client with HTTP code 200, so they do not trigger
// the catch block below.
documentHelper.writeDataToOfficeDocument("response");
handleAADErrors(exchangeResponse);
} else {
/*const response = await sso.makeGraphApiCall(exchangeResponse.access_token);
documentHelper.writeDataToOfficeDocument(response);*/
const _EndPoint = "/me/messages";
const _UrlParams = "?$select=receivedDateTime,subject,isRead&$orderby=receivedDateTime&$top=10";
const response = await sso.getGraphData(exchangeResponse.access_token, _EndPoint, _UrlParams);
documentHelper.writeDataToOfficeDocument(response);
sso.showMessage("Your data has been added to the document.");
}
} catch (exception) {
if (exception.code) {
if (sso.handleClientSideErrors(exception)) {
fallbackAuthHelper.dialogFallback();
}
} else {
sso.showMessage("EXCEPTION: " + JSON.stringify(exception));
}
}
}
the code in documentHelper.js:
function writeDataToExcel(result) {
/*return Excel.run(function (context) {
const sheet = context.workbook.worksheets.getActiveWorksheet();
let data = [];
let userProfileInfo = filterUserProfileInfo(result);
for (let i = 0; i < userProfileInfo.length; i++) {
if (userProfileInfo[i] !== null) {
let innerArray = [];
innerArray.push(userProfileInfo[i]);
data.push(innerArray);
}
}
const rangeAddress = `B5:B${5 + (data.length - 1)}`;
const range = sheet.getRange(rangeAddress);
range.values = data;
range.format.autofitColumns();
return context.sync();
});*/
return Excel.run(function (context) {
const sheet = context.workbook.worksheets.getActiveWorksheet();
const rangeHeadings = sheet.getRange("A1:D1");
rangeHeadings.valueTypes = [["ReceivedDateTime", "subject", "Read?", "ID"]];
const _Contents = result.value;
for (let i = 0; i < _Contents.length; i++) {
if (_Contents !== null) {
let _TempArr = [];
_TempArr.push(_Contents[i].receivedDateTime);
_TempArr.push(_Contents[i].subject);
_TempArr.push(_Contents[i].isRead);
_TempArr.push(_Contents[i].id);
let _Data = [];
_Data.push(_TempArr);
const _rangeaddress = `A${2 + i}:D${2 + i}`;
const _rangedata = sheet.getRange(_rangeaddress);
_rangedata.values = _Data;
}
}
rangeHeadings.format.autofitColumns();
return context.sync();
});
}
When i run the add-in, it does not proceed after GET/ auth? as shown in below image.
Here are my permission in the Azure APP Registration:
I can't understand what is really happening. When i click on the button in the sideloaded task pane, nothing is sent from the Graph API as shown in the command prompt image. I am really grateful, if someone could point out where the error is.
I have defined the scopes in my manifiest file as well.
Please help.
I am creating excel file from user data but unfortunately its not generating file and even don't know what is the error so I can at-least try to solve that error.
Specially this issue occur in iOS platform only.
Please find below code to generate excel file:
public createXSLX(): Promise<any> {
return new Promise((resolve) => {
let sheet = XLSX.utils.json_to_sheet(this.data);
let wb = {
SheetNames: ["export"],
Sheets: {
"export": sheet
}
};
let wbout = XLSX.write(wb, {
bookType: 'xlsx',
bookSST: false,
type: 'binary'
});
function s2ab(s) {
let buf = new ArrayBuffer(s.length);
let view = new Uint8Array(buf);
for (let i = 0; i != s.length; ++i) view[i] = s.charCodeAt(i) & 0xFF;
return buf;
}
let blob = new Blob([s2ab(wbout)], { type: 'application/octet-stream' });
resolve(blob);
});
}
This above function works very well in android but in iOS its not generation file from provided data.
How I call above function code :
onExportNew = function (toEmail) {
this.createXSLX().then((xclBlob) => {
let time = new Date().getTime();
let fileName: string = "roster_" + time + ".xlsx";
var fs = ''
if (this.platform.is('ios')){
fs = this.file.documentsDirectory;
}else{
fs = this.file.externalDataDirectory;
}
console.log("File Path:- ",fs)
this.file.writeFile(fs, fileName, xclBlob, true).then(() => {
let fp = fs + fileName;
let email = {
// to: 'lmahajan#cisco.com',
// cc: 'erika#mustermann.de',
// bcc: ['john#doe.com', 'jane#doe.com'],
to: toEmail,
attachments: [fp],
subject: 'Roster Excel File',
body: '<h1>PFA</h1>',
isHtml: true
};
this.emailComposer.open(email).then(() => {
this.showDone = true;
}).catch(() => {
let toast = this.toastCtrl.create({
message: 'Could not open email composer',
duration: 3000
});
toast.present();
});
}).catch(() => {
this.displayAlert('Error', 'error creating file at: ' + fs);
});
}).catch(() => {
console.log("Excel file creation error");
});
}
Guide me if missing anything in above code.
Thanks in advance!
For example, I have a car1 that was first owner by the manufacturer and then it was transferred over to the retailer and then to the user
In the fabcar example, I can know who is its current owner by i don't know who is the previous owner.
Is there a way to do it?
Here is the http://hyperledger-fabric.readthedocs.io/en/latest/write_first_app.html example I was following
Is not implemented in the chaincode. To do this you could implement a new method which returns the history of the asset.
Here the link to the official documentation for nodeJS (you can find it also for GoLang):
https://fabric-shim.github.io/ChaincodeStub.html#getHistoryForKey__anchor
Here an example:
async queryValueHistory(stub,args){
if (args.length != 1) {
throw new Error('Incorrect number of arguments. Expecting identifier ex: CAR01');
}
let carId = args[0];
let iterator = await stub.getHistoryForKey(carId);
let allResults = [];
while (true) {
let res = await iterator.next();
if (res.value && res.value.value.toString()) {
let jsonRes = {};
console.log(res.value.value.toString('utf8'));
jsonRes.TxId = res.value.tx_id;
jsonRes.Timestamp = res.value.timestamp;
jsonRes.IsDelete = res.value.is_delete.toString();
try {
jsonRes.Value = JSON.parse(res.value.value.toString('utf8'));
} catch (err) {
console.log(err);
jsonRes.Value = res.value.value.toString('utf8');
}
console.info(jsonRes);
allResults.push(jsonRes);
}
if (res.done) {
console.log('end of data');
try{
await iterator.close();
}catch(err){
console.log(err);
}
console.info(allResults);
return Buffer.from(JSON.stringify(allResults));
}
}
}
I'm using Xamarin forms, and in my application has a button to share the problem that is being in my android application I got doing with Intent but in my application ios'm not knowing how to do, someone could help me?
using android
public async Task<bool> Share(ImageSource image)
{
Intent shareIntent = new Intent(Intent.ActionSend);
bitmapToShare = await GetBitmap (image);
if (bitmapToShare != null) {
CreateDirectoryForPictures("Xpto");
var filePath = System.IO.Path.Combine (dir.AbsolutePath, string.Format("xpto_{0}.png",Guid.NewGuid()));
var stream = new FileStream (filePath, FileMode.Create);
bitmapToShare.Compress (Bitmap.CompressFormat.Png, 100, stream);
stream.Close ();
Java.IO.File file = new Java.IO.File (filePath);
shareIntent.SetType ("image/*");
shareIntent.PutExtra (Intent.ExtraStream, Android.Net.Uri.FromFile (file));
shareIntent.AddFlags (ActivityFlags.GrantReadUriPermission);
Forms.Context.StartActivity (Intent.CreateChooser (shareIntent, "Compartilhar"));
}
return true;
}
private static async Task ShareImageAsyc(ImageSource image, string message, string url = null)
{
var handler = image.GetHandler();
if (handler == null) return;
var uiImage = await handler.LoadImageAsync(image);
var items = new List<NSObject> { new NSString(message ?? string.Empty) };
if (!url.IsNullOrEmpty())
items.Add(new NSString(url));
items.Add(uiImage);
var controller = new UIActivityViewController(items.ToArray(), null);
UIApplication.SharedApplication.KeyWindow.RootViewController.GetTopViewController()
.PresentViewController(controller, true, null);
}
From: https://github.com/jimbobbennett/JimLib.Xamarin/blob/master/JimLib.Xamarin.ios/Sharing/Share.cs